1. 程式人生 > >java io詳解五:包裝流

java io詳解五:包裝流

我們在 Java IO 流的分類介紹  這篇部落格中介紹知道:

  根據功能分為節點流和包裝流(處理流)

    節點流:可以從或向一個特定的地方(節點)讀寫資料。如FileReader.

    處理流:是對一個已存在的流的連線和封裝,通過所封裝的流的功能呼叫實現資料讀寫。如BufferedReader.處理流的構造方法總是要帶一個其他的流物件做引數。一個流物件經過其他流的多次包裝,稱為流的連結。

 

1、前面講的字元輸入輸出流,位元組輸入輸出流都是節點流。那麼什麼是包裝流呢?

  ①、包裝流隱藏了底層節點流的差異,並對外提供了更方便的輸入\輸出功能,讓我們只關心這個高階流的操作

  ②、使用包裝流包裝了節點流,程式直接操作包裝流,而底層還是節點流和IO裝置操作

  ③、關閉包裝流的時候,只需要關閉包裝流即可

 

 

 

2、緩衝流

  

  緩衝流:是一個包裝流,目的是快取作用,加快讀取和寫入資料的速度。

  位元組緩衝流:BufferedInputStream、BufferedOutputStream

  字元緩衝流:BufferedReader、BufferedWriter

案情回放:我們在將字元輸入輸出流、位元組輸入輸出流的時候,讀取操作,通常都會定義一個位元組或字元陣列,將讀取/寫入的資料先存放到這個數組裡面,然後在取數組裡面的資料。這比我們一個一個的讀取/寫入資料要快很多,而這也就是緩衝流的由來。只不過緩衝流裡面定義了一個 陣列用來儲存我們讀取/寫入的資料,當內部定義的陣列滿了(注意:我們操作的時候外部還是會定義一個小的陣列,小陣列放入到內部陣列中),就會進行下一步操作。 

      

下面是沒有用緩衝流的操作:  

//1、建立目標物件,輸入流表示那個檔案的資料儲存到程式中。不寫碟符,預設該檔案是在該專案的根目錄下
            //a.txt 儲存的檔案內容為:AAaBCDEF
        File target = new File("io"+File.separator+"a.txt");
        //2、建立輸入流物件
        InputStream in = new FileInputStream(target);
        //3、具體的 IO 操作(讀取 a.txt 檔案中的資料到程式中)
            /**
             * 注意:讀取檔案中的資料,讀到最後沒有資料時,返回-1
             *  int read():讀取一個位元組,返回讀取的位元組
             *  int read(byte[] b):讀取多個位元組,並儲存到陣列 b 中,從陣列 b 的索引為 0 的位置開始儲存,返回讀取了幾個位元組
             *  int read(byte[] b,int off,int len):讀取多個位元組,並存儲到陣列 b 中,從陣列b 的索引為 0 的位置開始,長度為len個位元組
             */
        //int read():讀取一個位元組,返回讀取的位元組
        int data1 = in.read();//獲取 a.txt 檔案中的資料的第一個位元組
        System.out.println((char)data1); //A
        //int read(byte[] b):讀取多個位元組儲存到陣列b 中
        byte[] buffer  = new byte[10];//這裡我們定義了一個 長度為 10 的位元組陣列,用來儲存讀取的資料
        in.read(buffer);//獲取 a.txt 檔案中的前10 個位元組,並存儲到 buffer 陣列中
        System.out.println(Arrays.toString(buffer)); //[65, 97, 66, 67, 68, 69, 70, 0, 0, 0]
        System.out.println(new String(buffer)); //AaBCDEF[][][]
         
        //int read(byte[] b,int off,int len):讀取多個位元組,並存儲到陣列 b 中,從索引 off 開始到 len
        in.read(buffer, 0, 3);
        System.out.println(Arrays.toString(buffer)); //[65, 97, 66, 0, 0, 0, 0, 0, 0, 0]
        System.out.println(new String(buffer)); //AaB[][][][][][][]
        //4、關閉流資源
        in.close();

我們檢視 緩衝流的 JDK 底層原始碼,可以看到,程式中定義了這樣的 快取陣列,大小為 8192

  BufferedInputStream:

        

 

 

  BufferedOutputStream:

      

 

//位元組緩衝輸入流
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("io"+File.separator+"a.txt"));
        //定義一個位元組陣列,用來儲存資料
        byte[] buffer = new byte[1024];
        int len = -1;//定義一個整數,表示讀取的位元組數
        while((len=bis.read(buffer))!=-1){
            System.out.println(new String(buffer,0,len));
        }
        //關閉流資源
        bis.close();<br><br>
         
        //位元組緩衝輸出流
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("io"+File.separator+"a.txt"));
        bos.write("ABCD".getBytes());
        bos.close();
//字元緩衝輸入流
        BufferedReader br = new BufferedReader(
                new FileReader("io"+File.separator+"a.txt"));
        char[] buffer = new char[10];
        int len = -1;
        while((len=br.read(buffer))!=-1){
            System.out.println(new String(buffer,0,len));
        }
        br.close();
         
        //字元緩衝輸出流
        BufferedWriter bw = new BufferedWriter(
                new FileWriter("io"+File.separator+"a.txt"));
        bw.write("ABCD");
        bw.close();

 3、轉換流:把位元組流轉換為字元流

  InputStreamReader:把位元組輸入流轉換為字元輸入流

  OutputStreamWriter:把位元組輸出流轉換為字元輸出流

   

 

 用轉換流進行檔案的複製:

/**
         * 將 a.txt 檔案 複製到 b.txt 中
         */
        //1、建立源和目標
        File srcFile = new File("io"+File.separator+"a.txt");
        File descFile = new File("io"+File.separator+"b.txt");
        //2、建立位元組輸入輸出流物件
        InputStream in = new FileInputStream(srcFile);
        OutputStream out = new FileOutputStream(descFile);
        //3、建立轉換輸入輸出物件
        Reader rd = new InputStreamReader(in);
        Writer wt = new OutputStreamWriter(out);
        //3、讀取和寫入操作
        char[] buffer = new char[10];//建立一個容量為 10 的字元陣列,儲存已經讀取的資料
        int len = -1;//表示已經讀取了多少個字元,如果是 -1,表示已經讀取到檔案的末尾
        while((len=rd.read(buffer))!=-1){
            wt.write(buffer, 0, len);
        }
        //4、關閉流資源
        rd.close();
        wt.close();

 4、記憶體流(陣列流):

  把資料先臨時存在陣列中,也就是記憶體中。所以關閉 記憶體流是無效的,關閉後還是可以呼叫這個類的方法。底層原始碼的 close()是一個空方法

        

 

  ①、位元組記憶體流:ByteArrayOutputStream 、ByteArrayInputStream

//位元組陣列輸出流:程式---》記憶體
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        //將資料寫入到記憶體中
        bos.write("ABCD".getBytes());
        //建立一個新分配的位元組陣列。 其大小是此輸出流的當前大小,緩衝區的有效內容已被複制到其中。
        byte[] temp = bos.toByteArray();
        System.out.println(new String(temp,0,temp.length));
         
        byte[] buffer = new byte[10];
        ///位元組陣列輸入流:記憶體---》程式
        ByteArrayInputStream bis = new ByteArrayInputStream(temp);
        int len = -1;
        while((len=bis.read(buffer))!=-1){
            System.out.println(new String(buffer,0,len));
        }
         
        //這裡不寫也沒事,因為原始碼中的 close()是一個空的方法體
        bos.close();
        bis.close();

②、字元記憶體流:CharArrayReader、CharArrayWriter

//字元陣列輸出流
        CharArrayWriter caw = new CharArrayWriter();
        caw.write("ABCD");
        //返回記憶體資料的副本
        char[] temp = caw.toCharArray();
        System.out.println(new String(temp));
         
        //字元陣列輸入流
        CharArrayReader car = new CharArrayReader(temp);
        char[] buffer = new char[10];
        int len = -1;
        while((len=car.read(buffer))!=-1){
            System.out.println(new String(buffer,0,len));
        }

③、字串流:StringReader,StringWriter(把資料臨時儲存到字串中)

//字串輸出流,底層採用 StringBuffer 進行拼接
        StringWriter sw = new StringWriter();
        sw.write("ABCD");
        sw.write("帥鍋");
        System.out.println(sw.toString());//ABCD帥鍋
 
        //字串輸入流
        StringReader sr = new StringReader(sw.toString());
        char[] buffer = new char[10];
        int len = -1;
        while((len=sr.read(buffer))!=-1){
            System.out.println(new String(buffer,0,len));//ABCD帥鍋
        }

5、合併流:把多個輸入流合併為一個流,也叫順序流,因為在讀取的時候是先讀第一個,讀完了在讀下面一個流。

 

//定義位元組輸入合併流
        SequenceInputStream seinput = new SequenceInputStream(
                new FileInputStream("io/a.txt"), new FileInputStream("io/b.txt"));
        byte[] buffer = new byte[10];
        int len = -1;
        while((len=seinput.read(buffer))!=-1){
            System.out.println(new String(buffer,0,len));
        }
         
        seinput.close();