天天看點

JAVA:IO流 之 節點流與處理流(2)1. 流的分類2. 節點流3. 處理流

1. 流的分類

  • 按資料流的方向不同:輸入流,輸出流。
  • 按處理資料機關不同:位元組流,字元流。

    (1) 位元組流:資料流中最小的資料單元是位元組。

    (2)字元流:資料流中最小的資料單元是字元, Java中的字元是Unicode編碼,一個字元占用兩個位元組。

  • 按功能不同:節點流,處理流。

    (1)程式用于直接操作目标裝置所對應的類叫節點流。

    (2)程式通過一個間接流類去調用節點流類,以達到更加靈活友善地讀寫各種類型的資料,這個間接流類就是處理流。

2. 節點流

2.1 節點流的類型

JAVA:IO流 之 節點流與處理流(2)1. 流的分類2. 節點流3. 處理流
  • (1)File 檔案流。對檔案進行讀、寫操作 :FileReader、FileWriter、FileInputStream、FileOutputStream。、
  • (2)Memory

    1)從/向記憶體數組讀寫資料: CharArrayReader與 CharArrayWriter、ByteArrayInputStream與ByteArrayOutputStream。

    2)從/向記憶體字元串讀寫資料 StringReader、StringWriter、StringBufferInputStream。

  • (3)Pipe管道流。 實作管道的輸入和輸出(程序間通信): PipedReader與PipedWriter、PipedInputStream與PipedOutputStream。

2.2 節點流執行的圖示

JAVA:IO流 之 節點流與處理流(2)1. 流的分類2. 節點流3. 處理流

3. 處理流

3.1 處理流的類型

JAVA:IO流 之 節點流與處理流(2)1. 流的分類2. 節點流3. 處理流

- (1)Buffering緩沖流:在讀入或寫出時,對資料進行緩存,以減少I/O的次數:BufferedReader與BufferedWriter、BufferedInputStream與BufferedOutputStream。

- (2)Filtering 濾流:在資料進行讀或寫時進行過濾:FilterReader與FilterWriter、FilterInputStream與FilterOutputStream。

- (3)Converting between Bytes and Characters 轉換流:按照一定的編碼/解碼标準将位元組流轉換為字元流,或進行反向轉換(Stream到Reader):InputStreamReader、OutputStreamWriter。

- (4)Object Serialization 對象流 :ObjectInputStream、ObjectOutputStream。

- (5)DataConversion資料流: 按基本資料類型讀、寫(處理的資料是Java的基本類型(如布爾型,位元組,整數和浮點數)):DataInputStream、DataOutputStream 。

- (6)Counting計數流: 在讀入資料時對行記數 :LineNumberReader、LineNumberInputStream。

- (7)Peeking Ahead預讀流: 通過緩存機制,進行預讀 :PushbackReader、PushbackInputStream。

- (8)Printing列印流: 包含友善的列印方法 :PrintWriter、PrintStream。

3.2 處理流執行的圖示

JAVA:IO流 之 節點流與處理流(2)1. 流的分類2. 節點流3. 處理流

3.3 緩沖流

  • 【1】對I/O進行緩沖是一種常見的性能優化,緩沖流為I/O流增加了記憶體緩沖區,增加緩沖區的兩個目的:

    (1)允許Java的I/O一次不隻操作一個字元,這樣提高䇖整個系統的性能;

    (2)由于有緩沖區,使得在流上執行skip、mark和reset方法都成為可能。

  • 【2】緩沖流:它是要“套接”在相應的節點流之上,對讀寫的資料提供了緩沖的功能,

    提高了讀寫的效率,同時增加了一些新的方法。例如:BufferedReader中的readLine方法,

    BufferedWriter中的newLine方法。

  • 【3】J2SDK提供了4種緩存流,常用的構造方法為:
//字元輸入流
BufferedReader(Reader in)//建立一個32位元組的緩沖區
BufferedReader(Reader in, int size)//size為自定義緩存區的大小

//字元輸出流
BufferedWriter(Writer out)
BufferedWriter(Writer out, int size)

//位元組輸入流
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)

//位元組輸出流
BufferedOutputStream(OutputStream in)
BufferedOutputStream(OutputStream in, int size)
           
  • 【4】其他

    (1)緩沖輸入流BufferedInputSTream除了支援read和skip方法意外,還支援其父類的mark和reset方法;

    (2)BufferedReader提供了一種新的ReadLine方法用于讀取一行字元串(以\r或\n分隔);

    (3)BufferedWriter提供了一種新的newLine方法用于寫入一個行分隔符;

    (4)對于輸出的緩沖流,BufferedWriter和BufferedOutputStream,寫出的資料會先在記憶體中緩存,

    使用flush方法将會使記憶體的資料立刻寫出。

  • 示例1:
import java.io.*;
public class TestBufferStream1 {
  public static void main(String[] args) {
    try {
      FileInputStream fis = new FileInputStream(
          "d:\\JavaProject\\demo13\\ProcessingStream\\TestBufferStream1.java");
      BufferedInputStream bis = new BufferedInputStream(fis);
      int c = ;
      System.out.println((char)bis.read());
      System.out.println((char)bis.read());
      bis.mark();/*在目前輸入流的目前位置上做一個标志,允許最多再讀入100個位元組*/
      for(int i=;i<= && (c=bis.read())!=-;i++){
        System.out.print((char)c+" ");
      }
      System.out.println(); 
      bis.reset();/*把輸入指針傳回到以前所做的标志處*/
      for(int i=;i<= && (c=bis.read())!=-;i++){
        System.out.print((char)c+" ");
      }
      bis.close();
    } catch (IOException e) {e.printStackTrace();}
  }
}
           
  • 示例2:
import java.io.*;
public class TestBufferStream2
{
    public static void main(String[] args)
    {
    try{
    BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\JavaProject\\demo13\\BufferStream\\dat2.txt"));
    BufferedReader br = new BufferedReader(new FileReader("D:\\JavaProject\\demo13\\BufferStream\\dat2.txt"));
    String s = null;
    for(int i=;i<;i++)
    {
        s = String.valueOf(Math.random());//産生一個小于1的正的随機數,并轉換成字元串形式
        bw.write(s);//把字元串s寫入到dat2.txt檔案中
        bw.newLine();//寫入一個行分隔符
    }
    bw.flush();//使用flush方法将會使記憶體的資料立刻寫出

    while((s=br.readLine()) != null)
    {
        System.out.println(s);
    }
    bw.close();
    br.close();
    }
    catch(IOException e)
    {
        e.printStackTrace();
    }

    }
}
           

3.4 轉換流

  • 轉換流有兩種:

    (1)InputStreamReader:将位元組流轉換為字元流;

    (2)OutputStreamWriter:将字元流轉換為位元組流。

  • 什麼時候使用轉換流?由以下分析: 流對象很多,就要明确使用哪個流對象。
通過三點來完成: 
    、明确資料的來源和資料到達的目的地。
                 來源:輸入流 [InputStream,Reader]。 
                 目的:輸出流 [OutputStream,Writer]。 
    、操作的資料是否是純文字。  
                 是:字元流,使用Reader與Writer; 
                 否:位元組流,使用InputStream與OutputStream。 
    、明确要使用哪個具體的對象。 通過裝置來進行區分: 
                 源裝置:記憶體用數組,硬碟就加file,鍵盤用System.in; 
                 目的裝置:記憶體用數組,硬碟就加file,鍵盤用System.out。 
    、明确是否還需要其他額外功能:例如 
                ()是否需要較高的效率,即是否需要使用緩沖區,是就加上Buffered;
                ()是否需要轉換,是,就使用轉換流,InputStreamReader 和 OutputStreamWriter。
           
  • 用一個例子簡單的說明: 将鍵盤錄入的資料儲存到一個檔案中,輸入“over”時表示錄入結束。 詳細分析:
源:從InputStream,Reader中選擇; 因為是鍵盤錄入的是純文字,是以使用Reader。 
裝置:鍵盤,是以用System.in; 發現System.in是位元組流的操作,與Reader(字元流)沖突,
這時就要用到轉換流 InputStreamReader 。為了提高操作效率,使用緩沖技術,選擇BufferedReader。 

目的:從 OutputStream,Writer中選擇。 因為是文本檔案,是以選擇Writer。 
裝置:硬碟上,一個檔案,選擇FileWriter。 為了提高操作效率,使用緩沖技術,選擇BufferedWriter。 
           
  • 示例1:
import java.io.*; 
    class ReadinFile 
        { 
            public static void main(String[] args)throws IOException //這裡為了友善閱讀,先不做異常處理。 
            { 
                BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); 
                BufferedWriter bufw=new BufferedWriter(new FileWriter("readin.txt")); 
                String line=null; 
                while((line=bufr.readLine())!=null) 
                { 
                    if("over".equals(line)) break; 
                    bufw.write(line); 
                    bufw.newLine(); 
                } 
                bufw.close(); 
                bufr.close(); 
            } 
        }
           
  • 示例2:
import java.io.*;
public class TestTransForm 
{
    public static void main(String[] args) throws IOException //這裡為了友善閱讀,先不做異常處理。 
    {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        OutputStreamWriter osw = new OutputStreamWriter(
                                 new FileOutputStream("D:\\JavaProject\\demo13\\TransStream\\TransForm.txt",true));
        BufferedWriter bw = new BufferedWriter(osw);
        String str = null;
        str = br.readLine();
        while(str != null)
        {
            if(str.equalsIgnoreCase("exit")) break;
            bw.write(str);
            bw.newLine();
            str = br.readLine();
        }
        br.close();
        bw.close();
    }
}
           
  • 注意:

    (1)構造方法:public FileOutputStream(String name,boolean append) throws FileNotFoundException

    如果append為True,輸出位元組流就寫入檔案的末尾,而不是開頭(覆寫原來的内容);

    如果append為False,輸出位元組流就寫入檔案的開頭,即覆寫原來的内容從檔案開始處寫内容。

    (2)構造方法:public FileOutputStream(String name) throws FileNotFoundException

    每次覆寫原檔案的内容,從檔案開始處寫内容。

3.5 資料流——資料的存儲和資料恢複

  • 資料流:DataInputStream和DataOutputStream

    (0)DataInputStream和DataOutputStream是面向位元組的,是以要使用InputStream和OutputStream。

    (1)DataInputStream和DataOutputStream分别繼承InputStream和OutputStream,

    它們屬于處理流,需要分别“套接”在InputStream和OutputStream類型的節點流上。

    (2)DataInputStream和DataOutputStream提供了可以存取與機器無關的Java原始類資料(如:int,double等)的方法。

    (3)DataInputStream和DataOutputStream的構造方法:

DataInputStream(InputStream in)
     DataOutputStream(OutputStream out)
           
  • 示例1:
import java.io.*;
public class TestDataStream
{
    public static void main(String[] args) throws IOException
    {
        FileOutputStream fout = new FileOutputStream("D:/JavaProject/demo13_IO/DataStream/demo.txt",true);
        BufferedOutputStream bout = new BufferedOutputStream(fout);
        DataOutputStream dout = new DataOutputStream(bout);
        /*DataOutputStream,BufferedOutputStream,FileOutputStream這裡使用了流棧。*/

        dout.writeInt();
        dout.writeUTF("hello,中國");
        dout.writeFloat(f);
        dout.writeChar();/*97對應的是'a'*/
        dout.close();/*如果正在使用一個流棧,程式關閉最上面的一個流也就自動的關閉了棧中的所有底層流。*/

        FileInputStream fin = new FileInputStream("D:/JavaProject/demo13_IO/DataStream/demo.txt");
        BufferedInputStream bin = new BufferedInputStream(fin);
        DataInputStream din = new DataInputStream(bin);

        int i = din.readInt();
        String str = din.readUTF();
        float f = din.readFloat();
        char c = din.readChar();
        fin.close();/*如果正在使用一個流棧,程式關閉最上面的一個流也就自動的關閉了棧中的所有底層流。*/
        System.out.println("int:"+i+"\nString:"+str+"\nfloat:"+f+"\nchar:"+c);
    }

}
           
  • 編譯,運作:
D:\JavaProject\demo13_IO\DataStream>javac TestDataStream.java

D:\JavaProject\demo13_IO\DataStream>java TestDataStream
int:
String:hello,中國
float:
char:a
           
  • 注意:
int i = din.readInt();
        String str = din.readUTF();
        float f = din.readFloat();
        char c = din.readChar();
        /*此段代碼的順序不能亂,要保證先寫入的先讀出來的原則,否則會出現錯誤。
        *    是以,我們在寫代碼的時候,我們必須:
        *         要麼為檔案中的資料采用固定的格式;
        *         要麼将額外的資訊儲存到檔案中,以便能夠對其進行解析以确定資料的尋訪位置。
        */