參考鏈接: Java中的字符流與字節流 Character Stream對比Byte Stream
菜鳥舉例理解字節流和字符流區別?
?按照uft8編碼方式存儲文檔?
?文檔存儲路徑在D盤下?
/**
* 按照utf8格式存儲文檔
*/
public static void storeDataByUTF8(){
? ? String path = "D:" + File.separator + "textutf8.txt";
? ? File file = new File(path);
? ? try {
? ? ? ? PrintWriter pw = new PrintWriter(file,"utf-8");
? ? ? ? for(int i=0;i<5;i++){
? ? ? ? ? ? pw.write(i+":"+"字節流與字符流!!!"+"\r\n");
? ? ? ? }
? ? ? ? pw.flush();
? ? ? ? pw.close();
? ? } catch (FileNotFoundException | UnsupportedEncodingException e) {
? ? ? ? e.printStackTrace();
? ? }
}?
?對比使用BufferedReader和FileInputStream按照byte讀取文檔(按照字節流方式讀取)?
?使用BufferedReader按照byte讀取文檔代碼如下:?
public static void readDataWithArray(){
? ? String path = "D:" + File.separator + "textutf8.txt";
? ? File file = new File(path);
? ? try{
? ? ? ? FileInputStream fis = new FileInputStream(file);
? ? ? ? ? InputStreamReader isr = new InputStreamReader(fis,"utf-8");
? ? ? ? BufferedReader in = new BufferedReader(isr);
? ? ? ? byte[] b = new byte[2048];
? ? ? ? int temp = 0;
? ? ? ? int len = 0;
? ??????
? ? ? ? while((temp=in.read())!=-1){? // -1是結束符
? ? ? ? ? ? b[len] = (byte)temp;
? ? ? ? ? ? if(len<2047)
? ? ? ? ? ? ? ? len++;
? ? ? ? ? ? else
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? in.close();
? ? ? ? System.out.println(new String(b,0,len,"utf-8"));
? ??????
? ? }catch(Exception e){
? ? ? ? e.printStackTrace();
? ? ? ? System.out.println("While reading the data, the program threw out exceptions");
? ? }
?
}?
?輸出結果發生了亂碼:?
0:W?AW&A
1:W?AW&A
2:W?AW&A
3:W?AW&A
4:W?AW&A?
?FileInputStream按照byte讀取文檔代碼如下:?
public static void readDataWithArray(){
? ? String path = "D:" + File.separator + "textutf8.txt";
? ? File file = new File(path);
? ? try{
? ? ? ? FileInputStream in = new FileInputStream(file);
? ? ? ? //InputStreamReader isr = new InputStreamReader(fis,"utf-8");
? ? ? ? //BufferedReader in = new BufferedReader(isr);
? ??????
? ? ? ? byte[] b = new byte[2048];
? ? ? ? int temp = 0;
? ? ? ? int len = 0;
? ??????
? ? ? ? while((temp=in.read())!=-1){? // -1是結束符
? ? ? ? ? ? b[len] = (byte)temp;
? ? ? ? ? ? if(len<2047)
? ? ? ? ? ? ? ? len++;
? ? ? ? ? ? else
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? in.close();
? ? ? ? System.out.println(new String(b,0,len,"utf-8"));
? ??????
? ? }catch(Exception e){
? ? ? ? e.printStackTrace();
? ? ? ? System.out.println("While reading the data, the program threw out exceptions");
? ? }
?
}?
?輸出結果正常:?
0:字節流與字符流!!!
1:字節流與字符流!!!
2:字節流與字符流!!!
3:字節流與字符流!!!
4:字節流與字符流!!!?
?以上兩段代碼不同之處只是讀取文本的流不同,其他代碼相同。要回答這個問題,首先來理解一下為什么要編碼??
?為什么要編碼?
?不知道大家有沒有想過一個問題,那就是為什么要編碼?我們能不能不編碼?要回答這個問題必須要回到計算機是如何表示我們人類能夠理解的符號的,這些符號也就是我們人類使用的語言。由于人類的語言有太多,因而表示這些語言的符號太多,無法用計算機中一個基本的存儲單元—— byte 來表示,因而必須要經過拆分或一些翻譯工作,才能讓計算機能理解。我們可以把計算機能夠理解的語言假定為英語,其它語言要能夠在計算機中使用必須經過一次翻譯,把它翻譯成英語。這個翻譯的過程就是編碼。所以可以想象只要不是說英語的國家要能夠使用計算機就必須要經過編碼。 所以總的來說,編碼的原因可以總結為:?
計算機中存儲信息的最小單元是一個字節即 8 個 bit,所以能表示的字符范圍是 0~255 個人類要表示的符號太多,無法用一個字節來完全表示要解決這個矛盾必須需要一個新的數據結構 char,從 char 到 byte 必須編碼?
?為什么兩者的結果那么不同呢??
?在Java中byte是1個字節(8個bit),char是2個字節; 最基礎的流InputStream和OutputStream是按照字節讀取的(byte)。?
/**
?* Reads a byte of data from this input stream. This method blocks
?* if no input is yet available.
?*
?* @return? ? ?the next byte of data, or <code>-1</code> if the end of the
?*? ? ? ? ? ? ?file is reached.
?* @exception? IOException? if an I/O error occurs.
?*/
public int read() throws IOException {
? ? return read0();
}?
?但是BufferedReader類的read()方法返回的是char。所以沒有處理好編碼原因的第三個原因。?
public class BufferedReader extends Reader {
? ? private char cb[];? // char數組的緩存
? ? private int nChars, nextChar;
? ? ...
? ? ? ? /**
? ? ?* Reads a single character.
? ? ?*
? ? ?* @return The character read, as an integer in the range
? ? ?*? ? ? ? ?0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
? ? ?*? ? ? ? ?end of the stream has been reached
? ? ?* @exception? IOException? If an I/O error occurs
? ? ?*/
? ? public int read() throws IOException {
? ? ? ? synchronized (lock) {
? ? ? ? ? ? ensureOpen();
? ? ? ? ? ? for (;;) {
? ? ? ? ? ? ? ? if (nextChar >= nChars) {
? ? ? ? ? ? ? ? ? ? fill();
? ? ? ? ? ? ? ? ? ? if (nextChar >= nChars)
? ? ? ? ? ? ? ? ? ? ? ? return -1;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (skipLF) {
? ? ? ? ? ? ? ? ? ? skipLF = false;
? ? ? ? ? ? ? ? ? ? if (cb[nextChar] == '\n') {
? ? ? ? ? ? ? ? ? ? ? ? nextChar++;
? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return cb[nextChar++];
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ??
}?
?舉個詳細的例子: 按照 ISO-8859-1 編碼字符串“I am 君山”用 ISO-8859-1 編碼,下面是編碼結果:??
?從上圖看出7個char 字符經過ISO-8859-1 編碼轉變成7個byte 數組,ISO-8859-1是單字節編碼,中文“君山”被轉化成值是3f的byte。3f也就是“?”字符,所以經常會出現中文變成“?”很可能就是錯誤的使用了 ISO-8859-1這個編碼導致的。中文字符經過 ISO-8859-1編碼會丟失信息,通常我們稱之為“黑洞”,它會把不認識的字符吸收掉。由于現在大部分基礎的 Java 框架或系統默認的字符集編碼都是 ISO-8859-1,所以很容易出現亂碼問題。?
?以上總結只是舉例了一個簡單的例子,希望能通過這個例子使得你對Java字節流和字符流的區別有個感性的認識。如果需要了解兩者的區別,強烈建議大家看看另一篇博客《深入分析 Java 中的中文編碼問題》。?
?如果博客寫得有什么問題,請各請各位大神指出。