I/O流

小年年發表於2018-07-26

      I/O流按說是Java中的一個基礎,學是大家都學過,整體是有大概印象的,但從開始我就沒有太理清各個流之間的關係和用法,日常用的時候大致能寫,有一些複雜的、記不清的都是從網上進行百度,大致看懂之後Ctrl+C與Ctrl+V進行修修改改,懂那個意思了但是沒多久就會忘了,這幾天通過看書和閱讀大家的blog,自己更清晰了一些,整理了一下。

      整個大的分類,不二話,還是那四個,InputStream,OutputStream,Reader,Writer是所有流的基類(別抬槓,我知道RandomAccessFile除外)具體用到什麼功能,就要去對InputSteam的方法進行重寫,使用他們子類來完成。在這裡我來整理一下提他們之間的關係和用法。

一、InputStream

BufferedInputStream 位元組緩衝輸入流
InputStream FileInputStream 位元組檔案輸入流
ByteArrayInputStream 位元組陣列輸入流

      其中BufferedInputStream應該是大家最經常用到的,為的是在使用InputStream時可以增加緩衝區,好處就是在於可以減少系統開支,增加效率,打個比喻,如果不用緩衝就像是一捧一捧的舀水,而用緩衝就像是一桶一桶的舀水,就可以減少兩邊來回跑的時間,也就是通過這樣的方式來增加I/O效率。

      FileInputStram則是檔案輸入流了,在讀入流檔案的時候就需要他了(如影音,圖片等檔案),通常可以把他再套上BufferedInputStream使用。

BufferedInputStream bis = new BufferedInputStream(System.in);
複製程式碼

      因為BufferedInputStream 的預設緩衝區大小是8092KB也就是8M,所以在檔案較小的時候(相較於8M)用過BufferedInputStream之後的I/O操作明顯效率會比直接用FIleInputStream提高了很多,在等於8M或者大於8M的時候相差就不大了,但是整體來說還是推薦用BufferedInputStream的。

      BtyeArrayInputStream 這個起到位元組與流之間的橋樑,可以將位元組陣列轉換成流。

InputStream is = new ByteArrayInputStream(new byte[1024]);
new String(is.toString().getBytes(),"UTF-8");
複製程式碼

二、OutputStream

BufferedOutputStream 位元組緩衝輸出流
OutputStream FileOutputStream 位元組檔案輸出流
ByteArrayOutputStream 位元組陣列輸出流

      同樣的,BufferedOutputStream是大家經常用到的,與BufferedInputStream同理,增加緩衝區,減少系統開支,增加I/O效率。

      FileOutputStream則是檔案輸出流,在寫出檔案的用的就是他,也是通常可以把他套上BufferedOutputStream使用。

BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream(""));
複製程式碼

      ByteArrayOutputStream 你可以將要輸出的位元組陣列讀到記憶體緩衝區,然後要進行你所需要的操作。

 ByteArrayOutputStream bos = new ByteArrayOutputStream();

 bos.write(new byte[1024]);
複製程式碼

三、Reader

BufferedReader 字元緩衝流
Reader InputStreamReader 位元組->字元輸入流
FileReader 字元檔案輸入流

      Reader也同樣提供了對應的字元緩衝流來提高效率。

      InputStreamReader則是搭起了位元組流與字元流的橋樑。

Reader reader = new InputStreamReader(System.in);​
複製程式碼

      FileReader是當讀取檔案為​文字檔案時(如TXT檔案),可以直接用FIleReader進行操作,同樣的在外面可以套上BufferedReader進行使用。

BufferedReader br= new BufferedReader(new FileReader(""));
複製程式碼

四、Writer

BufferedWriter 字元輸出流
Writer OutputStreamWriter 位元組->字元輸出流
FileWriter 字元檔案輸出流
PrintWriter 列印流

      Writer有他對應的BufferedWriter來增加I/O效率。

      OutputStreamWriter也是搭起了字元流與位元組流的橋樑。

Writer writer = new OutputStreamWriter(System.err);
複製程式碼

      FileWriter是需要將字元寫入檔案時,可以直接用FIleWriter進行操作,同樣的在外面可以套上BufferedWriter進行使用。

BufferedWriter writer = new BufferedWriter(new FileWriter(""));
複製程式碼

      但是Writer有一個BufferedWriter的加強類(可以這麼理解)-PrintWriter,一般情況下推薦使用PrintWriter對外進行輸出,他和BufferedWriter相比較來說,具有幾個優點。

  1. PrintWriter的print、println方法可以接受任意型別的引數,而BufferedWriter的write方法只能接受字元、字元陣列和字串。

  2. PrintWriter的println方法自動新增換行,BufferedWriter需要顯示呼叫newLine方法。

  3. PrintWriter的構造方法更廣,可通過指定引數,實現自動重新整理快取(autoflush),而BufferedWriter需要通過flush方法來進行重新整理。

  4. 同時PrintWriter在過程中不會丟擲異常,如果關心異常,則要用checkError()來進行檢視。

五、總結

      上面就是常見流的四大基類以及各自的子類,下面寫幾個對於流的一些日常使用例子。

      案例1:通過oss的sdk拿到byte位元組流之後,要在頁面上進行內容的載入(txt為文件)。

StringBulider sb = new StringBuilder();  //  宣告好最後返回的字串,先用StringBuilder型別

byte[] bytes = new byte[8096];  //這裡new一個位元組陣列模擬從oss上拿到陣列

InputStream input = new ByteArrayInputeStream(bytes);  //將位元組數字轉成位元組輸入流。

Reader reader = new InputStreadmReader(input,"UTF-8"); //將位元組輸入流轉成字元輸入流,字元格式使用utf-8

BufferedReader br = new BufferReader(reader);   //套上緩衝流

String line = "";  //每次讀到的字元

whiel((line = reader.readLine()) != null) {  //每次去讀檔案的一行

sb.append(line).append("\n"); //將讀到的一行內容給sb加上去,並且加換行符。
}
複製程式碼

      最後將sb.toString進行返回就可以了,前端可以用pre標籤直接接收以保持在後端已經設定好的格式內容。

      案例2:寫的一個將流進行字元轉換的工具類。一開始程式碼是這樣寫的。

 InputeStream in = System.in;

 StringBulid sb = new StringBuild;

 byte[] bytes = new byte[256];

 int len  = 0;

 while((len = in.read(bytes)) != -1) {

 sb.append(new String(bytes, 0, len));

 }
複製程式碼

      最後把sb.toString進行return就結束,小夥伴們看著有啥問題沒?其實邏輯沒錯啊,這樣寫也沒錯啊,但是!!!但是日常使用中偶爾會有幾個亂碼出現,我就沒想明白啊,字符集的問題吧,系統預設字符集給的是utf-8啊,不應該有亂碼啊,而且偶爾蹦出來幾個字是亂碼,這是什麼鬼,後來還是被被人一語道破,臥槽,Java中的字符集為utf-8的漢字是佔3個位元組,如果字數比較多的話,每次到最後取的位元組就取不完整,就可能造成亂碼問題,經過修復後程式碼如下。

InputeStream in = System.in;

ByteArrayOutputstream bos= new ByteArratOutputStream();

byte[] bytes = new byte[256];

int len  = 0;

while((len = in.read(bytes)) != -1) {

bos.write(bytes, 0, len);

}
複製程式碼

      因為每次都是將取出來的位元組都存放到位元組陣列裡,所以即使這一次取的將一個完整的漢字的3個位元組打亂,也沒有關係,會在下一次取數的時候給拼過來,只是將完整的位元組輸入流轉換成了位元組陣列輸出流,最後將new String(bos.toByteArray(),"UTF-8")進行返回就可以了。

      以上是對I/O使用的一些心得體會,和大家分享,希望能夠指出不足,互相交流。

相關文章