IO系列之字節流和字符流

IO流的分類

  • 根據處理數據類型的不同分爲:字符流和字節流

  • 根據數據流向不同分爲:輸入流和輸出流

進行輸入、輸出操作一般都會按照如下步驟進行:

  • 通過File類定義一個要操作文件的路徑
  • 通過字節流或字符流的子類對象爲父類對象實例化
  • 進行數據的讀(輸入)、寫(輸出)操作
  • 數據流屬於資源操作,資源操作必須關閉

java.io包定義了兩類流:

  • 字節流(JDK 1.0):InputStream、OutputStream
  • 字符流(JDK 1.1):Writer、Reader

1. 字節流

1.1 字節輸出流(OutputStream)

OutputStream這個抽象類是表示字節輸出流的所有類的超類。

輸出流接收輸出字節並將其發送到某個接收器。

需要定義OutputStream子類的應用OutputStream必須至少提供一個寫入一個字節輸出的方法。

OutputStream類提供了三個輸出的方法:

  • 輸出單個字節:public abstract void write(int b)
  • 輸出全部字節數組:public void write(byte[] b)
  • 輸出部分字節數組:public void write(byte[] b,int off,int len)

OutputStream本身屬於抽象類,如果想爲抽象類進行對象的實例化操作,需要使用抽象類的子類,進行文件操作可以使用FileOutputStream子類。在這個子類中定義瞭如下構造方法:

  • FileOutputStream(File file) 創建文件輸出流以寫入由指定的File對象表示的文件
  • FileOutputStream(File file, boolean append) 文件內容追加

使用全部字節數組進行輸出示例:

     //1. 定義要輸出的文件路徑
        File file = new File("E:"+File.separator+"demo"+File.separator+"test.txt");
        //如果目錄不存在則先創建目錄
        if(file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }

        //2. 應該使用OutputStream和其子類進行對象的實例化,此時目錄存在,文件還不存在
        OutputStream outputStream = new FileOutputStream(file);

        //3. 進行文件內容的輸出
        String str = "好好學習,天天向上";
        //將字符串轉爲byte數組
        byte[] data = str.getBytes();

        outputStream.write(data);

        //4. 關閉資源
        outputStream.close();

使用部分字節數組輸出示例

 //1. 定義要輸出的文件路徑
        File file = new File("E:"+File.separator+"demo"+File.separator+"study.txt");
        //如果目錄不存在則先創建目錄
        if(file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }

        //2. 應該使用OutputStream和其子類進行對象的實例化,此時目錄存在,文件還不存在
        OutputStream outputStream = new FileOutputStream(file);

        //3. 進行文件內容的輸出
        String str = "我們要好好學習技術,然後找個好工作,多賺點錢,補貼家用,實現自我價值,成爲一個對社會有用的人";
        //將字符串轉爲byte數組
        byte[] data = str.getBytes();

        outputStream.write(data,0,6);

        //4. 關閉資源
        outputStream.close();
1.2 字節輸入流:InputStream

InputStream抽象類是表示輸入字節流的所有類的超類。

需要定義InputStream子類的應用InputStream必須始終提供一種返回輸入的下一個字節的方法。

InputSream提供了三個輸入的方法

  • public abstract int read() 從輸入流讀取數據的下一個字節
  • public int read(byte[] b) 從輸入流讀取一些字節數,並將它們存儲到緩衝區b 。 實際讀取的字節數作爲整數返回。 該方法阻塞直到輸入數據可用,檢測到文件結束或拋出異常。
  • public int read(byte[] b,int off,int len) 從輸入流讀取len字節的數據到一個字節數組。 嘗試讀取多達len個字節,但可以讀取較小的數字。 實際讀取的字節數作爲整數返回。該方法阻塞直到輸入數據可用,檢測到文件結束或拋出異常。

使用FileInputStream讀入文件示例

  //1. 定義要輸入的文件路徑
 File file = new File("E:"+File.separator+"demo"+File.separator+"study.txt");
//判斷文件是否存在後纔可以進行讀取
if(file.exists()){
    // 2. 使用FileInputStream進行讀取
    InputStream inputStream = new FileInputStream(file);
    //準備處理一個1024的數組
    byte[] data = new byte[1024];
    //字節數組的操作腳標
    int foot = 0;
    //表示每次讀取的字節數據
     int temp = 0;
    //讀取一個字節
    while((temp = inputStream.read()) != -1){
         if(temp != -1){
          data[foot++] = (byte)temp;
         }
    }
    //4. 關閉流
    inputStream.close();
    System.out.println("["+new String(data,0,foot)+"]");
    }
}

2. 字符流

2.1 字符輸出流:Writer

Writer是用於寫入字符流的抽象類。子類必須實現的唯一方法是write(char [],int,int),flush()和close()。 然而,大多數子類將覆蓋這裏定義的一些方法,以便提供更高的效率,或者附加功能。

Writer提供的常用方法

  • write(char[] cbuf) 寫入一個字符數組。
  • write(char[] cbuf, int off, int len) 寫入字符數組的一部分。
  • write(int c) 寫一個字符
  • write(String str) 寫一個字符串
  • write(String str, int off, int len) 寫一個字符串的一部分。
  • append(char c) 附加指定的字符
  • close() 關閉流,先刷新。
  • flush() 刷新流。

使用字符輸出流輸出字符串示例

 //1. 定義要輸出的文件路徑
 File file = new File("E:"+File.separator+"demo"+File.separator+"writer.txt");
//如果目錄不存在則創建
if(!file.getParentFile().exists()){
    file.getParentFile().mkdirs();
}

//2. 實例化Writer類對象
Writer out = new FileWriter(file);

//3. 進行內容輸出
String str = "好好學習,天天向上!!!";
//輸出字符串數據
out.write(str);

//4. 關閉流
out.close();
2.2 字符輸入流:Reader

用於讀取字符流的抽象類。 子類必須實現的唯一方法是read(char [],int,int)和close()。 然而,大多數子類將覆蓋這裏定義的一些方法,以便提供更高的效率以及附加的功能。

Reader提供的常用方法

  • read() 讀一個字符
  • read(char[] cbuf) 將字符讀入數組。
  • read(char[] cbuf, int off, int len) 將字符讀入數組的一部分。
  • read(CharBuffer target) 嘗試將字符讀入指定的字符緩衝區。
  • ready() 告訴這個流是否準備好被讀取。
  • close() 關閉流並釋放與之相關聯的任何系統資源。
  • mark(int readAheadLimit) 標記流中的當前位置。
  • reset() 重置流。

讀入文件可以使用子類FileReader,示例代碼如下:

 //1. 定義要輸入的文件路徑
File file = new File("E:"+File.separator+"demo"+File.separator+"writer.txt");
//判斷文件是否存在後纔可以進行讀取
if(file.exists()){
            
    // 2. 爲Reader類對象實例化
    Reader input = new FileReader(file);
            
    // 3. 進行數據讀取
    char[] c = new char[1024];
    int len = input.read(c);
            
    //4. 關閉流
    input.close();
    
    System.out.println(new String(c,0,len));
}

與字節輸入流相比結構幾乎一樣,只是數據類型由byte變爲char

3. 字節流與字符流的區別

  • 字節流直接與終端進行數據交互,字符流需要將數據經過緩存區處理後纔可以輸出
  • 讀寫單位不同:字節流以字節(8bit)爲單位,字符流以字符爲單位,根據碼錶映射字符,一次可能讀多個字節。
  • 字節流處理二進制數據,字符流處理文本文件
  • 字節流可以轉爲字符流,而字符流不能轉爲字節流
  • 進行中文處理時優先考慮字符流

4. 字節流轉換爲字符流

在java.io包裏面提供了兩個類:InputStreamReader和OutputStreamWriter用於將字節流轉爲字符流

名稱: InputStreamReader OutputStreamWriter
定義結構: public class InputStreamReader extends Reader InputStreamReader(InputStream in)
構造方法: public class OutputStreamWriter extends Writer OutputStreamWriter(OutputStream out)

InputStreamReader是將字節輸入流轉爲字符輸入流:它讀取字節,並使用指定的charset將其解碼爲字符。 它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的默認字符集。每個調用InputStreamReader的read()方法會導致從底層字節輸入流讀取一個或多個字節。 爲了使字節有效地轉換爲字符,可以從底層流讀取比滿足當前讀取操作所需的更多字節。

爲了最大的效率,請考慮在BufferedReader中包裝一個InputStreamReader。 例如:BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

OutputStreamWriter是將字節輸出流轉爲字符輸出流。 它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的默認字符集。
每次調用write()方法都會使編碼轉換器在給定字符上被調用。 所得到的字節在寫入底層輸出流之前累積在緩衝區中。 可以指定此緩衝區的大小。 請注意,傳遞給write()方法的字符不會緩衝。

爲了最大的效率,請考慮在BufferedWriter中包裝一個OutputStreamWriter,以避免頻繁的轉換器調用。 例如:Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

將字節輸出流轉爲字符輸出流示例

 File file = new File("E:"+ File.separator+"demo"+File.separator+"study.txt");
 if(!file.getParentFile().exists()){
    file.getParentFile().mkdirs();
        }
    //字節流
    OutputStream output = new FileOutputStream(file);

    //將字節流轉換爲字符流
    Writer out = new OutputStreamWriter(output);
    String c = "Hello World!";
    //進行輸出
    out.write(c);

    out.flush();
    out.close();

將字節輸入流轉爲字符輸入流示例

 File file = new File("E:"+ File.separator+"demo"+File.separator+"study.txt");
 if(!file.getParentFile().exists()){
    file.getParentFile().mkdirs();
        }

    //字節輸入流
    InputStream in = new FileInputStream(file);

    //將字節輸入流轉爲字符輸入流
    Reader input = new InputStreamReader(in);
    char[] c = new char[1024];
    //讀數據
    input.read(c);

    //關閉流
    input.close();

    System.out.println(new String(c));
  • 兩個轉換類都是字符流的子類,屬於字符流與字節流溝通的橋樑
發佈了94 篇原創文章 · 獲贊 94 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章