Java中是以流的形式來實現(xiàn)數(shù)據(jù)在網絡中的傳輸,而所說的“流”則是字節(jié)流。因為所有的數(shù)據(jù)的最底層都是以字節(jié)為單位存儲的,所以以字節(jié)為單位傳輸數(shù)據(jù)無疑是最簡單也是最有效的傳輸方式。
我們在學習Java的過程中,也經常接觸字符流,字符流顧名思義則是以字符為單位進行數(shù)據(jù)傳輸,但是其實字符流的應用面是很窄的,并不是所有的文件都存在字符的概念的,比如視頻文件、音頻文件、圖片文件,這些是無法以字符為單位進行傳輸?shù)摹W址髦荒軐ξ谋咀址M行操作。
提到字符,我們首先就會想到的是編碼,因為計算機存儲的是字節(jié),我們看到的卻是字符,這之間是靠編碼表對應起來的,那么這也就是本篇文章索要研究的內容—字符流編碼。
首先我們來看下面的案例:
案例顯示,Demo.java的項目編碼和b.txt的編碼格式一樣,則能夠正常寫入,不會亂碼。原理如下圖所示:
字符流,每一個字符流都存在一個緩沖區(qū),緩沖區(qū)的編碼格式是和項目的編碼格式一致的,上述代碼執(zhí)行流程是:字符串“黑馬”在FileWriter的緩沖區(qū)里面通過GBK編碼把漢字編碼成對應的字節(jié),然后底層通過字節(jié)流將字節(jié)寫入到b.txt。 很多人我們打開b.txt時看到的是“黑馬”這兩個字啊,并不是什么碼值啊。其實所有文件的底層都是字節(jié),子不過我們打開b.txt時,記事本軟件就通過此文件的編碼—GBK幫我們把碼值解碼成“黑馬”這兩個字了,所以我們看到的是黑馬。照這樣看來,如果b.txt的文件編碼是UTF-8的話,肯定就會亂碼,因為記事本會按照UTF-8進行解碼,效果如下圖所示:
接下來難點才真正的來臨(很多人看了下面的代碼和運行效果就蒙圈),我們把上圖的代碼改下(其他編碼格式不變),你會發(fā)現(xiàn)不亂碼了,如下圖:源碼如下:
[Java] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
|
public class Demo {[/align]
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter( "b.txt" );
String s = "黑馬" ;
byte [] bytes = s.getBytes( "UTF-8" );
String s1 = new String(bytes);
fw.write(s1);
fw.close();
}
}
|
很多人蒙圈的原因是因為,先把字符轉為了UTF-8 但是又通過new String(bytes)轉成了GBK啊,但是b.txt是UTF-8格式的編碼啊。為什么沒有亂碼呢? 下圖解釋的很詳細:
執(zhí)行流程是:先通過UTF-8編碼把“黑馬”編碼成幾個字節(jié)比如13 42 35 86 59 47,然后再通過GBK編碼,把該碼值解碼成對應的字符比如“傳智人”,然后“傳智人”進入緩沖區(qū)會通過GBK編碼編碼成剛才的字節(jié) 也就是13 42 35 86 59 47,然后再通過字節(jié)流寫入到b.txt中,當打開b.txt時,記事本軟件會按照此文件編碼格式-UTF-8解碼成“黑馬”,所以我們看到的是沒有亂碼。
總結:通過比價復雜的案例我們明白了一、每個字符流都存在緩沖區(qū),而且緩沖區(qū)的編碼是和項目編碼一致。二、字符流的底層依然是使用的字節(jié)流,而且還存在緩沖區(qū)的編碼動作,所以效率比字節(jié)流會慢很多,所以通常數(shù)據(jù)的傳輸我們都會使用字節(jié)流。三、文本文件的底層存儲的也是字節(jié),我們打開文件看到的字符,是記事本軟件所做的解碼。
作者:傳智播客JavaEE培訓學院
首發(fā):http://java.itcast.cn