Java IO(一) 字節流與字符流
在日常寫代碼中,用到文件讀取時會看到各種XXXInputStream、XXXOutputStream類,Java的基本IO流名字命名都是這樣一種形式,以至於很容易將IO類混淆,很難記住其中的區別,筆者將對Java IO中的類進行區別分析。首先從字節流和字符流的區別開始講起。
字節流和字符流的區別
-
字節流是用於讀寫字節數據的(比如圖像、視頻數據)
-
字符流是用於讀寫字符數據的,字符數據也就是我們能看懂的文本數據,事實上字符在文件中也是以字節形式存儲,字節數據需要進行字符集的轉換才能以字符的形式呈現。字符流就是用於直接讀取字符數據的,雖說時直接讀取字符數據,但其過程還是:讀取字節數據 → 字符集轉碼 → 字符 這樣一個過程,只是Java將整個過程封裝了便於直接讀取字符數據,有興趣的可以看源碼,字符流對象裏是創建了字節流對象的,比如FileReader裏有個構造函數如下:
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
接下來通過代碼進行一些分析:
import java.io.*;
/**
* 測試以字節流和字符流方式讀取中英文的結果
* 結果表明字節流讀取會使讀取出來的中文內容亂碼,而英文不會
* (每次讀取一個字節也不會造成英文亂碼,順便驗證了在文件中一個字符佔用一個字節)
* 而字符流讀取不會出現中文亂碼情況
*/
public class ByteStreamAndCharStream {
public static void main(String[] args) throws IOException {
// readByteStream1();
// readByteStream2();
readCharStream();
}
/**
* 以字節流方式讀取文件,一次讀取一個字節
* @throws IOException
*/
public static void readByteStream1() throws IOException {
File file = new File("testInput");
// 字節輸入流對象,指定數據源爲file對象
FileInputStream fis = new FileInputStream(file);
int ch = 0;
while ((ch = fis.read()) != -1){
System.out.print((char)ch);
}
System.out.println();
}
/**
* 以字節流方式讀取文件,一次讀取多個字節
* @throws IOException
*/
public static void readByteStream2() throws IOException {
File file = new File("testInput");
// 字節輸入流對象,指定數據源爲file對象
FileInputStream fis = new FileInputStream(file);
// byte[] buf = new byte[100]; 嘗試將buf的大小減小,可以發現中間出現更多的亂碼,
// 因爲每次只讀取1024個byte,出現一些字符恰好被截斷的情況
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1){
System.out.print(new String(buf,0,len));
}
System.out.println();
}
/**
* 以字符流方式讀取文件,一次讀取一個字符
* 讀取多個字符使用read(char[]),結果一樣,可自行實驗
* @throws IOException
*/
public static void readCharStream() throws IOException {
File file = new File("testInput");
FileReader fr = new FileReader(file);
int ch = 0;
while ((ch = fr.read()) != -1){
System.out.print((char)ch);
}
}
}
這段代碼的測試文件中包含中文和英文,三個方法的測試結果分別爲
- readByteStream1方法:中文全部亂碼,英文未出現亂碼,原因是一箇中文漢字在文件中佔用兩個字節而英文字母佔用一個字節,一次讀取一個字節會使每個中文字符截斷,造成亂碼
- readByteStream2方法:中文部分亂碼,每次讀取字節的長度越小,出現的亂碼越多,原因是字符串被拆分爲多個部分,每個部分的連接處可能會出現字符截斷,在該這個連接處就出現亂碼,每次讀取長度越小,截斷字符越多
- readCharStream方法:中文和英文都沒有出現亂碼,因爲FileReader是一次讀取一個字符。
以上就是字節流和字符流方式讀取文件的區別,讀者可運行以上代碼觀察測試結果。