Reader
Reader
是Java的IO庫提供的另一個輸入流接口。和
InputStream
的差別是,
InputStream
是一個位元組流,即以
byte
為機關讀取,而
Reader
是一個 字元 流,即以
char
為機關讀取:
InputStream | Reader |
---|---|
位元組流,以byte為機關 | 字元流,以char為機關 |
讀取位元組(-1,0~255):int read() | 讀取字元(-1,0~65535):int read() |
讀到位元組數組:int read(byte[] b) | 讀到字元數組:int read(char[] c) |
java.io.Reader
是所有字元輸入流的超類,它最主要的方法是:
這個方法讀取字元流的下一個字元,并傳回字元表示的
int
,範圍是 0~65535。如果已讀到末尾,傳回 -1。
FileReader
FileReader
是
Reader
的一個子類,它可以打開檔案并擷取
Reader
。下面的代碼示範了如何完整地讀取一個
FileReader
的所有字元:
public void readFile() throws IOException {
// 建立一個FileReader對象:
Reader reader = new FileReader("src/readme.txt");
for (;;) {
int n = reader.read(); // 反複調用read()方法,直到傳回-1
if (n == -1) {
break;
}
System.out.println((char)n); // 列印char
}
reader.close(); // 關閉流
}
如果我們讀取一個純
ASCII
編碼的文本檔案,上述代碼工作是沒有問題的。但如果檔案中包含中文,就會出現亂碼,因為
FileReader
預設的編碼與系統相關,例如,Windows系統的預設編碼可能是
GBK
,打開一個
UTF-8
編碼的文本檔案就會出現亂碼。
要避免亂碼問題,我們需要在建立
FileReader
時 指定編碼 :
和
InputStream
類似,
Reader
也是一種資源,需要保證出錯的時候也能正确關閉,是以我們需要用
try (resource)
來保證
Reader
在無論有沒有 IO錯誤 的時候都能夠正确地關閉:
try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8) {
// TODO
}
Reader
還提供了一次性讀取若幹字元并填充到
char[]數組
的方法:
public int read(char[] c) throws IOException
它傳回實際讀入的字元個數,最大不超過
char[]
數組的長度。傳回 -1 表示流結束。
利用這個方法,我們可以先設定一個緩沖區,然後,每次盡可能地填充緩沖區:
public void readFile() throws IOException {
try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) {
char[] buffer = new char[1000];
int n;
while ((n = reader.read(buffer)) != -1) {
System.out.println("read " + n + " chars.");
}
}
}
StringReader
StringReader
可以直接把
String
作為資料源:
try (Reader reader = new StringReader("Hello")) {
}
Writer
Reader
是帶編碼轉換器的
InputStream
,它把
byte
轉換為
char
,而
Writer
就是帶編碼轉換器的
OutputStream
,它把
char
轉換為
byte
并輸出。
Writer
和
OutputStream
的差別如下:
OutputStream | Writer |
---|---|
位元組流,以byte為機關 | 字元流,以char為機關 |
寫入位元組(0~255):void write(int b) | 寫入字元(0~65535):void write(int c) |
寫入位元組數組:void write(byte[] b) | 寫入字元數組:void write(char[] c) |
無對應方法 | 寫入String:void write(String s) |
Writer
是所有字元輸出流的超類,它提供的方法主要有:
- 寫入一個字元(0~65535):
;void write(int c)
- 寫入字元數組的所有字元:
;void write(char[] c)
- 寫入String表示的所有字元:
。void write(String s)
FileWriter
FileWriter
就是向檔案中寫入字元流的
Writer
。它的使用方法和
FileReader
類似:
try (Writer writer = new FileWriter("readme.txt", StandardCharsets.UTF_8)) {
writer.write('H'); // 寫入單個字元
writer.write("Hello".toCharArray()); // 寫入char[]
writer.write("Hello"); // 寫入String
}
StringWriter
StringWriter
也是一個基于記憶體的
Writer
。實際上,StringWriter 在内部維護了一個
StringBuffer
,并對外提供了
Writer
接口。