1. 程式人生 > 其它 >雜記六:Java IO之位元組流、字元流、緩衝流

雜記六:Java IO之位元組流、字元流、緩衝流

技術標籤:雜記java

在程式中所有的資料都是以流的方式進行傳輸或儲存的,程式需要資料的時候要使用輸入流讀取資料,而當程式需要將一些資料儲存起來的時候,就要使用輸出流完成。

1、流的特點

  • 先進先出:最先寫入輸出流的資料最先被輸入流讀取到。
  • 順序存取:可以一個接一個地往流中寫入一串位元組,讀出時也將按寫入順序讀取一串位元組,不能隨機訪問中間的資料。(RandomAccessFile除外)
  • 只讀或只寫:每個流只能是輸入流或輸出流的一種,不能同時具備兩個功能,輸入流只能進行讀操作,對輸出流只能進行寫操作。在一個數據傳輸通道中,如果既要寫入資料,又要讀取資料,則要分別提供兩個流。

2、位元組流、字元流和緩衝流的區別

位元組流:位元組流操作的單元是資料單元是8位的位元組。位元組流一般用來處理影象、視訊、音訊、PPT、Word等型別的檔案。位元組流本身沒有緩衝區,緩衝位元組流相對於位元組流,效率提升非常高。

字元流:字元流操作的是資料單元為16位的字元。字元流一般用於處理純文字型別的檔案,如TXT檔案等,但不能處理影象視訊等非文字檔案。字元流本身就帶有緩衝區,緩衝字元流相對於字元流效率提升就不是那麼大了。

Java中字元是採用Unicode標準,Unicode編碼中,一個英文為一個位元組,一箇中文為兩個位元組。而在UTF-8編碼中,一箇中文字元是3個位元組。如果使用位元組流處理中文,一次讀寫一個字元對應的位元組數就不會有問題,一旦將一個字元對應的位元組分裂開來,就會出現亂碼了。為了更方便地處理中文這些字元,Java才推出了字元流。

緩衝流:我們知道,程式與磁碟的互動相對於記憶體運算是很慢的,容易成為程式的效能瓶頸。減少程式與磁碟的互動,是提升程式效率一種有效手段。緩衝流,就應用這種思路:普通流每次讀寫一個位元組,而緩衝流在記憶體中設定一個快取區,緩衝區先儲存足夠的待操作資料後,再與記憶體或磁碟進行互動。這樣,在總資料量不變的情況下,通過提高每次互動的資料量,減少了互動次數。

3、常用的流相關類

3.1 位元組流:FileInputStream、FileOutputStream

效率較低,不建議使用

public class IOTest {
    public static void main(String[]
args) throws IOException { File file = new File("D:/test.txt"); write(file); System.out.println(read(file)); } public static void write(File file) throws IOException { OutputStream os = new FileOutputStream(file, true); // 要寫入的字串 String string = "慟哭六軍俱縞素,衝冠一怒為紅顏。"; // 寫入檔案 os.write(string.getBytes()); // 關閉流 os.close(); } public static String read(File file) throws IOException { InputStream in = new FileInputStream(file); // 一次性取多少個位元組 byte[] bytes = new byte[1024]; // 用來接收讀取的位元組陣列 StringBuilder sb = new StringBuilder(); // 讀取到的位元組陣列長度,為-1時表示沒有資料 int length = 0; // 迴圈取資料 while ((length = in.read(bytes)) != -1) { // 將讀取的內容轉換成字串 sb.append(new String(bytes, 0, length)); } // 關閉流 in.close(); return sb.toString(); } }

3.2 緩衝位元組流:BufferedInputStream、BufferedOutputStream

緩衝位元組流是為高效率而設計的,真正的讀寫操作還是靠FileOutputStream和FileInputStream,所以其構造方法入參是這兩個類的物件也就不奇怪了。

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        // 緩衝位元組流,提高了效率
        BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream(file, true));
        // 要寫入的字串
        String string = "慟哭六軍俱縞素,衝冠一怒為紅顏。";
        // 寫入檔案
        bis.write(string.getBytes());
        // 關閉流
        bis.close();
    }

    public static String read(File file) throws IOException {
        BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));
        // 一次性取多少個位元組
        byte[] bytes = new byte[1024];
        // 用來接收讀取的位元組陣列
        StringBuilder sb = new StringBuilder();
        // 讀取到的位元組陣列長度,為-1時表示沒有資料
        int length = 0;
        // 迴圈取資料
        while ((length = fis.read(bytes)) != -1) {
            // 將讀取的內容轉換成字串
            sb.append(new String(bytes, 0, length));
        }
        // 關閉流
        fis.close();
        return sb.toString();
    }
}

3.3 字元流:InputStreamReader、OutputStreamWriter

字元流適用於文字檔案的讀寫,OutputStreamWriter類其實也是藉助FileOutputStream類實現的,故其構造方法是FileOutputStream的物件

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        // OutputStreamWriter可以顯示指定字符集,否則使用預設字符集
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8");
        // 要寫入的字串
        String string = "慟哭六軍俱縞素,衝冠一怒為紅顏。";
        osw.write(string);
        osw.flush();
        osw.close();
    }

    public static String read(File file) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");
        // 字元陣列:一次讀取多少個字元
        char[] chars = new char[1024];
        // 每次讀取的字元陣列先append到StringBuilder中
        StringBuilder sb = new StringBuilder();
        // 讀取到的字元陣列長度,為-1時表示沒有資料
        int length;
        // 迴圈取資料
        while ((length = isr.read(chars)) != -1) {
            // 將讀取的內容轉換成字串
            sb.append(chars, 0, length);
        }
        // 關閉流
        isr.close();
        return sb.toString();
    }
}

3.4 便攜字元流:FileWriter、FileReader

Java提供了FileWriter和FileReader簡化字元流的讀寫,new FileWriter等同於new
OutputStreamWriter(new FileOutputStream(file, true))

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        FileWriter fw = new FileWriter(file, true);
        // 要寫入的字串
        String string = "慟哭六軍俱縞素,衝冠一怒為紅顏。";
        fw.write(string);
        fw.flush();
        fw.close();
    }

    public static String read(File file) throws IOException {
        FileReader fr = new FileReader(file);
        // 一次性取多少個位元組
        char[] chars = new char[1024];
        // 用來接收讀取的位元組陣列
        StringBuilder sb = new StringBuilder();
        // 讀取到的位元組陣列長度,為-1時表示沒有資料
        int length;
        // 迴圈取資料
        while ((length = fr.read(chars)) != -1) {
            // 將讀取的內容轉換成字串
            sb.append(chars, 0, length);
        }
        // 關閉流
        fr.close();
        return sb.toString();
    }
}

3.5 緩衝字元流:BufferedReader、BufferedWriter

public class IOTest {
    public static void main(String[] args) throws IOException {
        File file = new File("D:/test.txt");
        write(file);
        System.out.println(read(file));
    }
    public static void write(File file) throws IOException {
        // BufferedWriter fw = new BufferedWriter(new OutputStreamWriter(new
        // FileOutputStream(file, true), "UTF-8"));
        // FileWriter可以大幅度簡化程式碼
        BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));
        // 要寫入的字串
        String string = "慟哭六軍俱縞素,衝冠一怒為紅顏。";
        bw.flush();
        bw.write(string);
        bw.close();
    }

    public static String read(File file) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(file));
        // 用來接收讀取的位元組陣列
        StringBuilder sb = new StringBuilder();
        // 按行讀資料
        String line;
        // 迴圈取資料
        while ((line = br.readLine()) != null) {
            // 將讀取的內容轉換成字串
            sb.append(line);
        }
        // 關閉流
        br.close();
        return sb.toString();
    }
}

關於flush

flush是將緩衝區的資料強制寫入,其實在close的時候,也會進行一次flush的,因此close之前其實可以不用專門做flush的。但是在某些情況下,流比較大,在寫的過程中,可以進行階段性的flush。flush只在輸出流中使用。

字元流自帶緩衝區,在使用字元流進行輸出,又沒有close關閉流時,若想先輸出前面的內容或者釋放緩衝區,就得使用flush將緩衝區內容寫到檔案中。

位元組流沒有緩衝區,所以不需要flush。但BufferedOutputStream是個特例,它是帶緩衝區的位元組流,它的緩衝區每8192個位元組就會將內容輸出一次。如果緩衝區內容不到8192個位元組,又想輸出的時候,就得使用flush方法。

關於緩衝字元流

因為字元流自帶緩衝區,所以緩衝字元流對於普通字元流的效能提升並不明顯。我們使用緩衝字元流主要是想使用它的**readLine()、newLine()**方法。