第8次文章:其他流

  • 2019 年 10 月 8 日
  • 筆記

各位小夥伴兒,大家周末愉快哈

回到學校,開始科研,開始好好奮鬥咯
一、節點流

1、位元組數組 位元組 節點流

在兩台電腦上進行數據的相互的傳輸

輸入流 :ByteArrayInputStream

使用方法:read(byte[] b,int off,int len) +close()

輸出流 :ByteArrayOutputStream

使用方法:write(byte[] b,int off,int len) +toByteArray() + close() 不要使用多態

例如:

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.ByteArrayInputStream;  import java.io.ByteArrayOutputStream;  import java.io.IOException;  import java.io.InputStream;    public class ByteArrayDemo01 {    public static void main(String[] args) throws IOException {  read(write());  }  /**   * 寫出操作   * 位元組輸出流與文件輸出有些不同,因為位元組輸出流有新增方法,所以不可以使用多態   * @throws IOException   */  public static byte[] write() throws IOException {  //目標位置  byte[] dest ;  //選擇流  這裡有不同點:沒有將目標位置和輸出流進行關聯  ByteArrayOutputStream bos = new ByteArrayOutputStream();  //操作 寫出  String msg = "位元組輸入流與文件輸入流一致";  byte[] info = msg.getBytes();  bos.write(info, 0, info.length);  //獲取數據  dest = bos.toByteArray();  //釋放資源  bos.close();  return dest;  }    /**   * 位元組輸入流(ByteArrayInputStream)與文件輸入流一致(FileInputStream)   * @throws IOException   */  public static void read(byte[] src) throws IOException {  //數據源  使用外部傳入的方式來獲取    //選擇流。通過流,打開另一端電腦的數據,所以不能在數據源的地方進行列印輸出  InputStream is = new BufferedInputStream(//緩衝流  new ByteArrayInputStream(src)//節點流  );    //操作  byte[] info =new byte[1024];  int len = 0;  while(-1 != (len=is.read(info))) {  System.out.println(new String(info,0,len));  }    //釋放資源  is.close();//此處的close是一個空命令,兩台電腦之間不需要釋放資源  }    }

在寫出操作的時候,與文件輸出流不同的是:位元組輸出流沒有和寫出的目標位置相關聯,而是直接將內容寫進位元組數組輸出流中,然後使用位元組數組輸出流將內容轉化為位元組數組,並返回給目標位置。

二、處理流

1、基本類型 + String 保留數據+類型

輸入流:DateInputStream readXxx

輸出流:DateOutputStream writeXxx

在之前的IO流中,我們僅僅是將字元相關的資訊保存在了相應的文件中,卻沒有注意各個保存的內容參數的類型,比如int,double,float,long,String等等,那麼這樣的保存,在我們後期的調用相關數據時,難以快速確定各個參數的類型,所以會降低效率。現在使用DateInputStream和DateOutputStream時,就可以有效的避免這樣的問題。保存數據的時候,同時保存數據相對應的類型。

例如下面的實例:

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.BufferedOutputStream;  import java.io.ByteArrayInputStream;  import java.io.ByteArrayOutputStream;  import java.io.DataInputStream;  import java.io.DataOutputStream;  import java.io.IOException;  import java.io.InputStream;    /**   * 數據類型(基本類型+String)處理流   * 在保存時,同時保存數據以及其對應的數據類型   */  public class DataDemo2 {    public static void main(String[] args) throws IOException {  byte[] data = write();  read(data);  System.out.println(data.length);  }    /**   * 數據+類型   從位元組數組中讀取   * @throws IOException   */  public static void read(byte[] src) throws IOException {    //選擇流  //選擇位元組輸入流  InputStream is = new ByteArrayInputStream(src);  DataInputStream dis = new DataInputStream(  new BufferedInputStream(  is  )  );    //操作 讀取的順序必須與寫出的順序一致 必須存在才能讀取  double point = dis.readDouble();  long num = dis.readLong();  String str = dis.readUTF();  System.out.println(point+"--->"+num+"--->"+str);  //釋放資源  dis.close();  }    /**   * 數據+類型     輸出到位元組數組   * @param destPath   * @throws IOException   */  public static byte[] write() throws IOException {  double point = 2.5;  long num = 100L;  String str = "數據類型";    //創建目的地  byte[] dest = null;    //選擇流  //選擇位元組數組輸出流  ByteArrayOutputStream bos = new ByteArrayOutputStream();  DataOutputStream dos = new DataOutputStream(//數據類型處理流  new BufferedOutputStream(//緩衝處理流  bos//建立聯繫  )  );  //寫出的順序很重要,因為後續在告訴用戶的過程中,需要告訴用戶第幾個參數是什麼含義  dos.writeDouble(point);  dos.writeLong(num);  dos.writeUTF(str);  dos.flush();    //獲取數據  dest = bos.toByteArray();    //釋放資源  dos.close();  return dest;  }    }

在讀取最後的寫出結果時,可以直接識別出寫出的結果是什麼類型的,這樣就可以大大的提高運行效率。

2、引用類型(對象) 保留數據+類型

反序列化:輸入流:ObjectInputStream readObject()

序列化:輸出流:ObjectOutputStream writeObject()

注意:

1)先序列化後反序列化;但序列化的順序必須和序列化的順序相同

2)不是所有的對象都可以序列化,需要對象實現介面java.io.Serializable

不是對象的所有屬性都需要序列化,可以在不需要序列化的屬性前面加上修飾符transient

例如:

1)創建Employee類,實現介面java.io.Serializable,同時利用transient修飾屬性name,使得name不進行序列化。

package com.peng.IO.others;  /**   * 空介面只是一個標識   *   */  public class Employee implements java.io.Serializable{//此處是一個空介面  //transient表示該屬性不需要序列化  private transient String name;  private double salary;    public Employee(String name, double salary) {  super();  this.name = name;  this.salary = salary;  }  public Employee() {    }  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public double getSalary() {  return salary;  }  public void setSalary(double salary) {  this.salary = salary;  }    }

2)對Employee對象進行序列化寫出以及反序列化讀取

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.BufferedOutputStream;  import java.io.File;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.IOException;  import java.io.ObjectInputStream;  import java.io.ObjectOutputStream;  import java.util.Arrays;    /**   * 數據類型(不僅限於基本數據類型,可以為引用數據類型,對象)處理流   * 1、序列化------>寫出  ObjectOutputStream   * 2、反序列化----->讀取 ObjectInputStream   *   * 不是所有的對象都可以序列化 java.io.NotSerializableException   * 不是所有的屬性都需要序列化 transient   *   */  public class ObjectDemo01 {    public static void main(String[] args) throws IOException, ClassNotFoundException {  seri("E:\java學習\test\seri.txt");  read("E:\java學習\test\seri.txt");  }  //反序列化  讀取  public static void read(String srcPath) throws FileNotFoundException, IOException, ClassNotFoundException {  //創建源  File src = new File(srcPath);  //選擇流 ObjectInputStream  ObjectInputStream ois = new ObjectInputStream(  new BufferedInputStream(  new FileInputStream(src)  )  );    //操作  Object obj = ois.readObject();  if (obj instanceof Employee) {  Employee temp = (Employee) obj;  System.out.println(temp.getName());  System.out.println(temp.getSalary());  }    Object obj1 = ois.readObject();  int[] arr = (int[]) obj1;  System.out.println(Arrays.toString(arr));    //釋放資源  ois.close();  }      //序列化  寫出  public static void seri(String destPath) throws FileNotFoundException, IOException {  Employee temp = new Employee("鵬程萬里",1000);  int[] arr = {1,2,3,4,5};  //創建源  File dest = new File(destPath);    //選擇流ObjectOutputStream  ObjectOutputStream dos = new ObjectOutputStream(  new BufferedOutputStream(//緩衝流  new FileOutputStream(dest)//節點流  )  );    dos.writeObject(temp);  dos.writeObject(arr);  dos.flush();  dos.close();    }    }

3)查看結果

null  1000.0  [1, 2, 3, 4, 5]

由於我們使用了transient對Employee對象的name屬性進行了修飾,所以在反序列化(讀取)的時候,並沒有輸出Employee對象的name屬性。

注意:

1)數組也屬於一個對象,所以在序列化的時候,可以將數組也作為一個對象進行序列化和反序列化。

2)在反序列化(讀取)時,讀取的順序必須與序列化(寫出)的順序相同,所以在寫出的時候,需要注意寫出的對象的順序,避免後期讀取的時候報錯。

3)寫出的文件內容是給電腦查看的內容,保留有各個屬性的類型,所以我們查看路徑「E:java學習testseri.txt」的內容時,所看到的是一堆亂碼。如下圖所示:

三、列印流

1、在java編程中,我們經常使用System.out.println()命令,將我們想要看到的變數列印在控制台上,便於我們看到變數的具體內容。而System.out.println()命令也屬於IO流中的一種,也屬於處理流中的一種。列印流的使用方法,也和其他的處理流的使用方法相同:

package com.peng.IO.others;    import java.io.BufferedOutputStream;  import java.io.File;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.PrintStream;    /**   * PrintStream  列印流---->處理流   */  public class PrintStreamDemo01 {  public static void main(String[] args) throws FileNotFoundException {  System.out.println("test");  PrintStream ps = System.out;  ps.println(false);  //輸出到文件  File src = new File("E:\java學習\test\print.txt");  ps = new PrintStream(//處理流  new BufferedOutputStream(//緩衝流  new FileOutputStream(src)//節點流--- 位元組流  )  );  ps.println("peng is very good");  ps.flush();  ps.close();  }    }

通過上面的程式碼可以看出來,列印流(PrintStream)使用的是其自己的方法println方法,將字元串寫出到目標文件中。

2、在列印流中,有幾個基本的知識點這裡提一下:

1)三個常量:

  • System.in 輸入流—–鍵盤輸入
  • System.out 輸出流—–控制台輸出
  • System.err 輸出流—–控制台輸出 其中,System.out和System.err的功能完全相同,都是將相應的提示資訊輸出到控制台上,唯一的差別就是在控制台上輸出的資訊的字體顏色不同,System.out輸出到控制台上的字體顏色默認為黑色,而System.err輸出到控制台上的字體顏色默認為紅色。

2)重定向

由於在上述的三個常量,默認的輸入與輸出都是在控制台上進行,假如用戶需要將資訊輸出到相應的文本文件中,而不是顯示在控制台上,那麼就需要使用重定向,將其輸入與輸出的位置進行重新關聯。

例如:

package com.peng.IO.others;    import java.io.BufferedInputStream;  import java.io.BufferedOutputStream;  import java.io.File;  import java.io.FileDescriptor;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.FileOutputStream;  import java.io.InputStream;  import java.io.PrintStream;  import java.util.Scanner;    public class SystemDemo01 {    public static void main(String[] args) throws FileNotFoundException {  test();  }    public static void test() throws FileNotFoundException {  //重定向  System.setOut(new PrintStream(//本質上還是一個輸出流 ---- 處理流  new BufferedOutputStream(  new FileOutputStream(  new File("E:/java學習/test/print.txt")  )  ),true  )  );  //此時的輸出已經不在控制台中了,將所需要輸出的字元輸出到指定的文件中  System.out.println("test");//控制台----->文件  System.out.println("one produce two, two produce three,three produce all things.");    //重新回到控制台  System.setOut(new PrintStream(  new BufferedOutputStream(  new FileOutputStream(  FileDescriptor.out  )  ),true  )  );  System.out.println("back.........");  }    }

重定向主要使用三條命令進行實現:SetIn();SetOut();SetErr(),三條命令分別設定輸入,輸出,以及輸出錯誤資訊的位置。

控制台的目標位置同樣使用三條命令進行實現:FileDescriptor.in;FileDescriptor.out;FileDescriptor.err,三條命令分別代表輸入,輸出和錯誤資訊在返回到控制台上的位置。

四、裝飾設計模式

1、類與類之間的關係

1)依賴:形參||局部變數

2)關聯:屬性

聚合:屬性 整體與部分 不一致的生命周期 人與手

組合:屬性 整體與部分 一致的生命周期 人與大腦

3)繼承:父子類關係

4)實現:介面與實現類的關係

2、IO流中使用的屬於裝飾設計模式

也就是利用不同的處理流,對節點流進行包裝處理。比如在老師講課的時候,使用擴音器,就屬於將老師的講課聲音進行了擴大,對原聲進行了裝飾。

例如:

1)我們先建立一個聲音類

package com.peng.IO.pattern;    public class Voice {  private int voice = 10;  public Voice() {    }  public Voice(int voice) {  super();  this.voice = voice;  }  public int getVoice() {  return voice;  }  public void setVoice(int voice) {  this.voice = voice;  }  public void say() {  System.out.println(voice);  }  }

2)然後建立一個擴音器

package com.peng.IO.pattern;    public class Amplifier {  private Voice voice;  public Amplifier() {    }  public Amplifier(Voice voice) {  super();  this.voice = voice;  }  public Voice getVoice() {  return voice;  }  public void setVoice(Voice voice) {  this.voice = voice;  }  public void say() {  System.out.println(voice.getVoice()*1000);  }  }

3)最後應用一下

package com.peng.IO.pattern;    public class App {    public static void main(String[] args) {  Voice v =new Voice(20);  v.say();  Amplifier am = new Amplifier(v);  am.say();  }  }

最終的結果當然就是我們將聲音的數值擴大了1000倍,這就是簡單的使用了裝飾模式。類比在IO流的使用上,我們依舊是首先利用處理流,使用處理流對緩衝流進行包裝,然後再利用緩衝流對節點流或者字元流進行包裝,最後實現我們需要的功能。

以上就是本周分享的內容咯!Java小白成長之路!Java小白在這裡陪你一起學Java,一起向上奮鬥!