上節我們介紹了如何以字節流的方式處理文件,我們提到,對於文本文件,字節流沒有編碼的概念,不能按行處理,使用不太方便,更適合的是使用字符流,本節就來介紹字符流。
我們首先簡要介紹下文本文件的基本概念、與二進制文件的區別、編碼、以及字符流和字節流的區別,然後我們介紹Java中的主要字符流,它們有:
除了這些類,Java中還有一個類Scanner,類似於一個Reader,但不是Reader的子類,可以讀取基本類型的字符串形式,類似於PrintWriter的逆操作。
理解了字節流和字符流後,我們介紹一下Java中的標准輸入輸出和錯誤流。
最後,我們總結一些簡單的實用方法。
基本概念
文本文件
上節我們提到,處理文件要有二進制思維。從二進制角度,我們通過一個簡單的例子解釋下文本文件與二進制文件的區別,比如說要存儲整數123,使用二進制形式保存到文件test.dat,代碼為:
DataOutputStream output = new DataOutputStream(new FileOutputStream("test.dat")); try{ output.writeInt(123); }finally{ output.close(); }
使用UltraEdit打開該文件,顯示的卻是:
{
打開十六進制編輯器,顯示的為:
在文件中存儲的實際有四個字節,最低位字節7B對應的十進制數是123,也就是說,對int類型,二進制文件保存的直接就是int的二進制形式。這個二進制形式,如果當成字符來解釋,顯示成什麼字符則與編碼有關,如果當成UTF-32BE編碼,解釋成的就是一個字符,即{。
如果使用文本文件保存整數123,則代碼為:
OutputStream output = new FileOutputStream("test.txt"); try{ String data = Integer.toString(123); output.write(data.getBytes("UTF-8")); }finally{ output.close(); }
代碼將整數123轉換為字符串,然後將它的UTF-8編碼輸出到了文件中,使用UltraEdit打開該文件,顯示的就是期望的:
123
打開十六進制編輯器,顯示的為:
文件中實際存儲的有三個字節,31 32 33對應的十進制數分別是49 50 51,分別對應字符'1','2','3'的ASCII編碼。
編碼
在文本文件中,編碼非常重要,同一個字符,不同編碼方式對應的二進制形式可能是不一樣的,我們看個例子,對同樣的文本:
hello, 123, 老馬
UTF-8編碼,十六進制為:
英文和數字字符每個占一個字節,而每個中文占三個字節。
GB18030編碼,十六進制為:
英文和數字字符與UTF-8編碼是一樣的,但中文不一樣,每個中文占兩個字節。
UTF-16BE編碼,十六進制為:
無論是英文還是中文字符,每個字符都占兩個字節。UTF-16BE也是Java內存中對字符的編碼方式。
字符流
字節流是按字節讀取的,而字符流則是按char讀取的,一個char在文件中保存的是幾個字節與編碼有關,但字符流給我們封裝了這種細節,我們操作的對象就是char。
需要說明的是,一個char不完全等同於一個字符,對於絕大部分字符,一個字符就是一個char,但我們之前介紹過,對於增補字符集中的字符,比如'