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相比較來說,具有幾個優點。
-
PrintWriter的print、println方法可以接受任意型別的引數,而BufferedWriter的write方法只能接受字元、字元陣列和字串。
-
PrintWriter的println方法自動新增換行,BufferedWriter需要顯示呼叫newLine方法。
-
PrintWriter的構造方法更廣,可通過指定引數,實現自動重新整理快取(autoflush),而BufferedWriter需要通過flush方法來進行重新整理。
-
同時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使用的一些心得體會,和大家分享,希望能夠指出不足,互相交流。