1. 程式人生 > >系統學習 Java IO (十三)----字符讀寫 Reader/Writer 及其常用子類

系統學習 Java IO (十三)----字符讀寫 Reader/Writer 及其常用子類

file void .html 多個 同名 處理 ati www. 什麽

目錄:系統學習 Java IO---- 目錄,概覽

Reader

Reader 類是 Java IO API 中所有 Reader 子類的基類。 Reader 類似於 InputStream ,除了它是基於字符而不是基於字節的。 換句話說,Java Reader 用於讀取文本,而 InputStream 用於讀取原始字節。

Writer

Writer 類是 Java IO API 中所有 Writer 子類的基類。 Writer 就像一個 OutputStream ,除了它是基於字符而不是基於字節的。 換句話說,Writer 用於寫入文本,而 OutputStream 用於寫入原始字節。
Writer 通常連接到某些數據目標,如文件,字符數組,網絡套接字等。

Unicode中的字符

許多應用程序使用 UTF(UTF-8或UTF-16)來存儲文本數據。 可能需要一個或多個字節來表示 UTF-8 中的單個字符。 在 UTF-16 中,每個字符需要 2 個字節來表示。 因此,在讀取或寫入文本數據時,數據中的單個字節可能與 UTF 中的一個字符不對應。 如果只是通過 InputStream 一次讀取或寫入 UTF-8 數據的一個字節,並嘗試將每個字節轉換為字符,可能不會得到正確的文本。

Reader 類能夠將字節解碼為字符。 只需要告訴Reader要解碼的字符集。 這是在實例化 Reader 時執行的(當實例化其中一個子類時)。 通常會直接使用 Reader 子類而不是 Reader。Writer 同理。

讀取

部分方法如下:
|方法|描述|
|-|-|
| void mark(int readAheadLimit) | 標記流中的當前位置。
| int read() | 讀取單個字符。
| int read(char[] cbuf) |將字符讀入數組。
|abstract int read(char[] cbuf, int off, int len) | 將字符讀入數組的某一部分。
| int read(CharBuffer target) | 試圖將字符讀入指定的字符緩沖區。
|boolean ready() | 判斷是否準備讀取此流。

具體的使用需要參考對應的子類。

和 InputStream 類似,如果 read() 方法返回 -1 ,則 Reader 中沒有更多數據要讀取,並且可以關閉它。-1 作為 int 值,而不是-1作為byte或char值。

將字節流包裝成字符流 InputStreamReader/OutputStreamWrite

InputStreamReade

InputStreamReade 類用於包裝 InputStream ,從而將基於字節的輸入流轉換為基於字符的 Reader 。 換句話說,InputStreamReader 將 InputStream 的字節解釋為文本而不是數字數據,是字節流通向字符流的橋梁。
為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

通常用於從文件(或網絡連接)中讀取字符,其中字節表示文本。 例如,一個文本文件,其中字符編碼為 UTF-8 。 可以使用InputStreamReader 來包裝 FileInputStream 以讀取此類文件。
一個示例如下:

 InputStream inputStream = new FileInputStream("D:\\test\\1.txt");
        Reader inputStreamReader = new InputStreamReader(inputStream);

        int data = inputStreamReader.read();
        while (data != -1) {
            char c = (char) data;
            System.out.print(c);
            data = inputStreamReader.read();
        }
        inputStreamReader.close();

首先創建一個 FileInputStream ,然後將其包裝在 InputStreamReader 中。 其次,該示例通過InputStreamReader 從文件中讀取所有字符.
註意:為清楚起見,此處已跳過正確的異常處理。 要了解有關正確異常處理的更多信息,請轉至目錄的 Java IO 異常處理。

指定字符集

底層 InputStream 中的字符將使用某些字符編碼進行編碼。 此字符編碼稱為字符集,Charset。 兩種常用字符集是 ASCII 和 UTF8(在某些情況下為UTF-16)。

默認字符集可能因為環境不同而不同,所以建議告訴 InputStreamReader 實例 InputStream 中的字符用什麽字符集進行編碼。 這可以在 InputStreamReader 構造函數中指定,可以只提供字符集的名字字符串,在底層會調用Charset.forName("UTF-8")進行轉換的。 以下是設置Java InputStreamReader使用的字符集的示例:

InputStream inputStream = new FileInputStream("D:\\test\\1.txt");
Reader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
關閉 InputStreamReader

同樣建議使用 Java try with resources 來關閉流。

try(InputStreamReader inputStreamReader =
    new InputStreamReader(input)){
    int data = inputStreamReader.read();
    while(data != -) {
        System.out.print((char) data));
        data = inputStreamReader.read();
    } 
}

OutputStreamWriter

OutputStreamWriter 類用於包裝 OutputStream ,從而將基於字節的輸出流轉換為基於字符的 Writer 。

如果需要將字符寫入文件,OutputStreamWriter 非常有用,例如編碼為 UTF-8或UTF-16。 然後可以將字符(char值)寫入 OutputStreamWriter ,它將正確編碼它們並將編碼的字節寫入底層的 OutputStream 。
一個簡單的示例如下:

OutputStream outputStream = new FileOutputStream("D:\\test\\1.txt");
Writer outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write("Hello OutputStreamWriter");
outputStreamWriter.close();

註意:為清楚起見,此處已跳過正確的異常處理。 要了解有關正確異常處理的更多信息,請轉至目錄的 Java IO 異常處理。

同 InputStreamReader,OutputStreamWriter 也可以使用指定的字符集輸出,如:
Writer outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");

關閉 OutputStreamReader

參考關閉 InputStreamReader 或 Java IO 異常處理。

讀寫文件 FileReader/FileWriter

FileReader

FileReader類使得可以將文件的內容作為字符流讀取。 它的工作方式與 FileInputStream 非常相似,只是 FileInputStream 讀取字節,而 FileReader 讀取字符。 換句話說,FileReader 旨在讀取文本。 取決於字符編碼方案,一個字符可以對應於一個或多個字節。

FileReader 假定您要使用運行應用程序的計算機的默認字符編碼來解碼文件中的字節。 這可能並不總是你想要的,但是不能改變它!
如果要指定其他字符解碼方案,請不要使用 FileReader 。 而是在 FileInputStream 上使用 InputStreamReader 。 InputStreamReader 允許您指定在讀取基礎文件中的字節時使用的字符編碼方案。

FileWriter

FileWriter 類可以將字符寫入文件。 在這方面它的工作原理與 FileOutputStream 非常相似,只是 FileOutputStream 是基於字節的,而 FileWriter 是基於字符的。 換句話說,FileWriter 用於寫文本。 一個字符可以對應於一個或多個字節,這取決於使用的字符編碼方案。
創建 FileWriter 時,可以決定是否要覆蓋具有相同名稱的任何現有文件,或者只是要追加內容到現有文件。 可以通過選擇使用的 FileWriter 構造函數來決定。

FileWriter(File file, boolean append) :根據給定的 File 對象構造一個 FileWriter 對象。 示例如下:

Writer fileWriter = new FileWriter("c:\\data\\output.txt", true);  // 追加模式
Writer fileWriter = new FileWriter("c:\\data\\output.txt", false); // 默認情況,直接覆蓋原文件

註意,只要成功 new 了一個 FileWriter 對象,沒有指定是追加模式的話,那不管有沒有調用 write() 方法,都會清空文件內容。

下面是一個讀和寫的例子:

public class FileRW {
    public static void main(String[] args) throws IOException {
        // 默認是覆蓋模式
        File file = new File("D:\\test\\1.txt");
        Writer writer1 = new FileWriter(file);
        writer1.write("string from writer1, ");
        writer1.close();

        Writer writer2 = new FileWriter(file, true);
        writer2.write("append content from writer2");
        writer2.close();


        Reader reader = new FileReader(file);
        int data = reader.read();
        while (data != -1) {
            // 將會輸出 string from writer1, append content from writer2
            System.out.print((char) data);
            data = reader.read();
        }
        reader.close();
    }
}

註意:為清楚起見,此處已跳過正確的異常處理。 要了解有關正確異常處理的更多信息,請轉至Java IO異常處理。

其他行為和 InputStreamReader 差不多,就不展開講了。

PipedReader/PipedWriter

讀寫管道 PipedReader 和 PipedWriter

PipedReader 類使得可以將管道的內容作為字符流讀取。 因此它的工作方式與 PipedInputStream 非常相似,只是PipedInputStream 是基於字節的,而不是基於字符的。 換句話說,PipedReader 旨在讀取文本。PipedWriter 同理。

構造器
方法 描述
PipedReader() 創建尚未連接的 PipedReader。
PipedReader(int pipeSize) 創建一個尚未連接的 PipedReader,並對管道緩沖區使用指定的管道大小。
PipedReader(PipedWriter src) 創建直接連接到傳送 PipedWriter src 的 PipedReader。
PipedReader(PipedWriter src, int pipeSize) 創建一個 PipedReader,使其連接到管道 writer src,並對管道緩沖區使用指定的管道大小。
PipedWriter() 創建一個尚未連接到傳送 reader 的傳送 writer。
PipedWriter(PipedReader snk) 創建傳送 writer,使其連接到指定的傳送 reader。
讀寫之前,必須先建立連接

PipedReader 必須連接到 PipedWriter 才可以讀 ,PipedWriter 也必須始終連接到 PipedReader 才可以寫。就是說讀寫之前,必須先建立連接,有兩種方式可以建立連接。

  1. 通過構造器創建,偽代碼如 Piped piped1 = new Piped(piped2);
  2. 調用其中一個的 connect() 方法,偽代碼如 Piped1.connect(Piped2);

並且通常,PipedReader 和 PipedWriter 由不同的線程使用。 註意只有一個 PipedReader 可以連接到同一個 PipedWriter 。
一個示例如下:

PipedWriter writer = new PipedWriter();
PipedReader reader = new PipedReader(writer);

writer.write("string form pipedwriter");
writer.close();

int data = reader.read();
while (data != -1) {
        System.out.print((char) data); // string form pipedwriter
        data = reader.read();
    }
reader.close();

註意:為清楚起見,這裏忽略了正確的 IO 異常處理,並且沒有使用不同線程,不同線程操作請參考 PipedInputStream 。

正如在上面的示例中所看到的,PipedReader 需要連接到 PipedWriter 。 當這兩個字符流連接時,它們形成一個管道。 要了解有關 Java IO 管道的更多信息,請參考 管道流 PipedInputStream 部分。

讀寫字符數組 CharArrayReader/CharArrayWriter

ByteArrayInputStream/ByteArrayOutputStream 是對字節數組處理,CharArrayReader/CharArrayWriter 則是對字符數組進行處理,其用法是基本一致的,所以這裏略微帶過。

CharArrayReader

CharArrayReader 類可以將 char 數組的內容作為字符流讀取。
只需將 char 數組包裝在 CharArrayReader 中就可以很方便的生成一個 Reader 對象。

CharArrayWriter

CharArrayWriter 類可以通過 Writer 方法(CharArrayWriter是Writer的子類)編寫字符,並將寫入的字符轉換為 char 數組。
在寫入所有字符時,CharArrayWriter 上調用 toCharArray() 能很方便的生成一個字符數組。

兩個類的構造函數:
方法 描述
CharArrayReader(char[] buf) 根據指定的 char 數組創建一個 CharArrayReader
CharArrayReader(char[] buf, int offset, int length) 根據指定的 char 數組創建一個 CharArrayReader
CharArrayWriter() 創建一個新的 CharArrayWriter ,默認緩沖區大小為 32
CharArrayWriter(int initialSize) 創建一個具有指定初始緩沖區大小的新 CharArrayWriter

註意:設置初始大小不會阻止 CharArrayWriter 存儲比初始大小更多的字符。 如果寫入的字符數超過了初始 char 數組的大小,則會創建一個新的更大的 char 數組,並將所有字符復制到新數組中。

一個使用實例如下:

CharArrayWriter writer = new CharArrayWriter();
writer.append(‘H‘);
writer.write("ello ".toCharArray());
writer.write("World");
char[] chars = writer.toCharArray();
writer.close();

CharArrayReader reader = new CharArrayReader(chars);
int data = reader.read();
while (data != -1) {
    System.out.print((char) data); // Hello World
    data = reader.read();
}
reader.close();

註意:為清楚起見,此處已跳過正確的異常處理。 要了解有關正確異常處理的更多信息,請轉至 Java IO 異常處理。

系統學習 Java IO (十三)----字符讀寫 Reader/Writer 及其常用子類