天天看點

Java - IO流詳解

文章目錄

  • ​​一、IO​​
  • ​​二、輸入輸出定義​​
  • ​​三、IO流常用基類​​
  • ​​四、字元流​​
  • ​​五、字元流的緩沖區​​
  • ​​BufferedWriter的close()方法​​
  • ​​六、位元組流​​
  • ​​七、位元組流的緩沖區​​
  • ​​BufferedOutputStream類調用父類FilterOutputStream中的close方法​​
  • ​​八、讀寫檔案的步驟​​
  • ​​九、位元組流與字元流的轉換​​
  • ​​十、轉換流的編碼和解碼​​

一、IO

IO流用來處理裝置之間的資料傳輸

Java對資料的操作是通過流的方式

Java用來操作流的對象都在IO包中

流按操作資料分為兩種 : 位元組流與字元流

流按流向分為 : 輸入流, 輸出流

二、輸入輸出定義

記憶體 – 硬碟(外設)

硬碟->記憶體 : 輸入(讀) – 讀取硬碟,持續輸入

記憶體->硬碟 : 輸出(寫) – 往硬碟寫,瘋狂輸出

将外設中的資料讀取到記憶體中 : 輸入

将記憶體中的資料寫入到外設中 : 輸出

位元組流的由來:

其實就是 : 位元組流讀取文字位元組資料後,不直接操作而是先查指定的編碼表,擷取對應的文字.

在對這個文字進行操作. 簡單說 : 位元組流 + 編碼表

三、IO流常用基類

  • 位元組流的抽象基類(頂層父類)
  • InputStream
  • OutputStream
  • 字元流的抽象基類
  • Reader
  • Writer

四、字元流

  • 字元輸入流
  • 字元輸出流

五、字元流的緩沖區

  • 緩沖區的出現提高了對資料的讀寫效率
  • 對應類
  • BufferedWriter
  • BufferedReader
  • 緩沖區要結合流才可以使用
  • 在流的基礎上對流的功能進行了增強

緩沖區的實際應用

超市推車,車裡面在放一個筐 ,存時友善,取得時候直接從車裡把筐提出來效率更快.

緩沖區類用到的設計模式

裝飾設計模式 : 對一組對象的功能進行增強!

BufferedWriter的close()方法

關閉資源前,需要先重新整理它(即先調用flush()方法)
Java - IO流詳解

六、位元組流

  1. 基本操作與字元流類相同
  2. 但它不僅可以操作字元,還可以操作其他媒體檔案
  • 位元組輸入流
  • 位元組輸出流

Tips:

中文漢字

編碼 中文漢字位元組數 英文字母位元組數
GB2312 2 1
GBK 2 1
GB18030 2 1
ISO-8859-1 1 1
UTF-8 3 1
UTF-16 4 4
UTF-16BE 2 2
UTF-16LE 2 2

七、位元組流的緩沖區

  • 對應類
  • BufferedInputStream
  • BufferedOutputStream

BufferedOutputStream類調用父類FilterOutputStream中的close方法

位元組流的緩沖區中的close()方法會先調用flush()方法,是以可以不去寫.
Java - IO流詳解

八、讀寫檔案的步驟

  1. 首先讀取檔案内容

    建立​​

    ​XXXReader/XXXInputStream對象​

    ​,并且傳入讀取檔案的路徑,進而達到和指定檔案關聯
  2. 建立一個緩沖區對象,将流對象添加到緩沖區

    建立​​

    ​BufferedXXX(Reader/InputStream)對象​

    ​,并将剛剛建立的流對象作為參數傳進緩沖區中
  3. 同前兩步,建立一個将要讀取的内容寫入到指定位置中(若指定檔案存在則覆寫,不存在則重新建立)

    然後再把建立的流對象添加到緩沖區中

  4. 開始讀取内容後将讀取到的内容寫入到輸出緩沖區中

    四種複制的方法(其中fis,fos,bufis,bufos為流對象或緩沖流對象的變量名)

    第一種 : 一個一個的讀取 : 不要使用這種方法,效率特别低!

int ch = 0;
    while ((ch = fis.read()) != -1) {
      fos.write(ch);
    }      

第二種 : 未使用緩沖區時,建立一個數組,每次讀取1K大小資料

byte[] buf = new byte[1024];

    int ch = 0;
    while ((ch = fis.read(buf)) != -1) {
        fos.write(buf, 0, ch);
    }      

第三種 : 使用緩沖區,先将資料存入到緩沖區中,之後在依次讀取緩沖區中的内容

int ch = 0;
    // 先将資料讀到緩沖區中,後從緩沖區中向硬碟中寫入資料
    while ((ch = bufis.read()) != -1) {
        bufos.write(ch);
    }      

第四種 : 直接擷取檔案的大小,直接建立一個檔案大小的數組,讀取檔案大小的内容後,在寫入

byte[] buf = new byte[bufis.available()];
    bufis.read(buf);
    bufos.write(buf);      
  1. 關閉資源

    ​​

    ​XXX.close();​

九、位元組流與字元流的轉換

InputStreamReader : 位元組流通向字元流的橋梁. 編碼(讀 , 把看不懂的轉換為看得懂的)

OutputStreamWriter : 字元流通向位元組流的橋梁. 解碼(寫 , 把看得懂的轉換為看不懂的)

執行個體

通過控制台輸入得到位元組流對象,後通過轉換為字元流,又使用緩沖流進行包裝字元流将寫入的資料讀取到字元緩沖流中.

之後寫入到輸出流中将資料輸出到控制台中

思路

  1. 明确源和目的

    源 : InputStream Reader

    目的 : OutputStream Writer

  2. 是否為純文字

    是 : 源 - Reader , 目的 - Writer

    否 : 源 - InputStream , 目的 - OutputStream

  3. 明确裝置

    源 : 鍵盤 : ​

    ​System.in​

    ​ 目的 : 控制台 : ​

    ​System.out​

  4. 明确額外功能

    需要轉換.因為都是位元組流,但是操作的卻是文本資料,是以使用字元流操作起來更為便捷

    ​InputStreamReader isr = new InputStreamReader(System.in);​

    ​​

    ​OutputStreamWriter osw = new OutputStreamWriter(System.out);​

    ​使其高效

    ​BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));​

import java.io.*;

public class TransStreamDemo {
    public static void main(String[] args) throws IOException {
        // in : “标準”輸入流。此流已打開并準備提供輸入資料。
        //      通常,此流對應于鍵盤輸入或者由主機環境或使用者指定的另一個輸入源。
        // 是以将鍵盤的輸入作為資料讀取到輸入流中
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        // “标準”輸出流。此流已打開并準備接受輸出資料。
        // 通常,此流對應于顯示器輸出或者由主機環境或使用者指定的另一個輸出目标
        // 是以資料寫入到輸出流中顯示在顯示器中
        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

        String line = null;

        while ((line = bufr.readLine()) != null) {
            if ("over".equals(line)) {
                return;
            }
            bufw.write(line.toUpperCase());
            // 寫入一個行分隔符
            bufw.newLine();
            bufw.flush();
        }

        // 位元組流緩沖區關閉資源前需要先重新整理該流
        bufr.close();
        bufw.close();
    }
}      

十、轉換流的編碼和解碼

​OutputStreamWriter osw = new OutputStream(new FileOutputStream("a.txt") , "GBK");​

​​

​FileWriter fw = new FileWriter("a.txt");​

這兩個代碼的功能是等同的
FileWriter : 其實就是轉換流指定了本機預設編碼表的展現。而且這個轉換流的子類對象,可以友善操作文本檔案。

        簡單來說:操作檔案的位元組流 + 本機預設的編碼表。
        
        這是按照預設碼表來操作檔案的邊界類。
        
        如果操作文本檔案需要明确具體的編碼。FileWriter就不行了。必須用轉換流!      

轉換流的另一個好處,可以融入編碼操作.

需求

将一個中文字元串資料按照指定的編碼表寫入到一個文本檔案中

  1. 目的 OutputStream,Writer
  2. 是否為純文字. Writer
  3. 裝置 : 硬碟 File

    ​​

    ​FileWriter fw = new FileWriter("a.txt"); fw.writer("你好");​

  4. 既然需求中已經明确了指定編碼表的動作.那就不可以使用FileWriter,因為FileWriter内部是使用預設的本地碼表.

    隻能使用其父類.OutputStreamWriter接受一個位元組輸出流對象,既然是操作檔案,那麼該對象是FileOutputStream.

​OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"), charsetName);​

  1. 源或者目的對應的裝置是位元組流,但操作的卻是文本資料,可以使用轉換作為橋梁.提高對文本操作的便捷.
  2. 一旦操作文本涉及到具體的指定編碼表時,必須使用轉換流.