Java講課筆記25:緩衝流、字符流與轉換流

零、本講學習目標

1、掌握字節流緩衝區的使用

2、掌握字節緩衝流的使用

3、掌握字符流操作文件的使用

4、掌握字符轉換流的使用

一、字節流的緩衝區

1、爲何引入字節流的緩衝區

在這裏插入圖片描述
上一講,我們利用文件字節流實現了文件拷貝,但是一個字節一個字節地讀寫,效率是十分低下的,這就好比從北京運送快遞到上海,如果有一萬件快遞,一件一件的運送就必須運輸一萬次,這樣的效率顯然非常低。爲了減少運輸次數,可以先把一批快遞裝在一個車廂中,這樣就可以成批地運送快遞,這時的車廂就相當於一個臨時緩衝區。同理,在文件拷貝過程中,通過以字節形式逐個拷貝,效率也非常低。爲此,可以定義一個字節數組緩衝區,在拷貝文件時,就可以一次性讀取多個字節的數據。

2、案例演示:採用文件字節流與字節流緩衝區實現文件拷貝

  • 將源文件source.png拷貝到net.hw.lesson25包裏
    在這裏插入圖片描述
  • 創建Example2501
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * 功能:拷貝文件
 *      採用文件字節流和字節流緩衝區
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2501 {
    public static void main(String[] args) throws Exception {
        // 創建文件字節輸入流
        FileInputStream fis = new FileInputStream("src/net/hw/lesson25/source.png");
        // 創建文件字節輸出流
        FileOutputStream fos = new FileOutputStream("src/net/hw/lesson25/target.png");

        // 獲取開始拷貝文件的系統時間
        long startTime = System.currentTimeMillis();

        // 定義字節數組作爲緩衝區
        byte[] buffer = new byte[1024];
        // 讀取源文件,寫入目標文件
        int len = 0;
        while ((len = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }

        // 獲取結束拷貝文件的系統時間
        long endTime = System.currentTimeMillis();

        // 輸出拷貝文件耗費時間
        System.out.println("拷貝文件耗費時間:" + (endTime - startTime) + "毫秒");
    }
}

在這裏插入圖片描述

  • 運行程序,查看結果
    在這裏插入圖片描述
  • 查看拷貝生成的目標文件target.png
    在這裏插入圖片描述
  • 對比上一講案例Example2408,逐個字節拷貝文件的耗時
    在這裏插入圖片描述
  • 說明:使用緩衝區讀寫文件可以有效地提高程序的傳輸效率。程序中的緩衝區就是一塊內存,該內存主要用於存放暫時輸入輸出的數據,由於使用了緩衝區減少了對文件的操作次數,因此可以顯著地提高讀寫數據的效率。

二、字節緩衝流

1、字節緩衝流概述

在這裏插入圖片描述
除了定義字節緩衝區來提高文件拷貝效率外,IO中還提供了兩個字節緩衝流來提高文件拷貝效率:BufferedInputStream和BufferedOutputStream。它們的構造方法中分別接收InputStream和OutputStream類型的對象作爲參數,在讀寫數據時提供緩衝功能。

2、案例演示:採用字節緩衝流但不採用字節流緩衝區拷貝文件

  • 創建Example2502
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * 功能:拷貝文件
 *      採用字節緩衝流,不採用字節流緩衝區
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2502 {
    public static void main(String[] args) throws Exception {
        // 創建緩衝字節輸入流
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("src/net/hw/lesson25/source.png"));
        // 創建緩衝字節輸出流
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("src/net/hw/lesson25/target.png"));

        // 獲取開始拷貝文件的系統時間
        long startTime = System.currentTimeMillis();

        // 讀取源文件,寫入目標文件
        int len = 0;
        while ((len = bis.read()) != -1) {
            bos.write(len);
        }

        // 獲取結束拷貝文件的系統時間
        long endTime = System.currentTimeMillis();

        // 輸出拷貝文件耗費時間
        System.out.println("拷貝文件耗費時間:" + (endTime - startTime) + "毫秒");
    }
}
  • 運行程序,查看結果
    在這裏插入圖片描述
  • 查看拷貝生成的目標文件target.png
    在這裏插入圖片描述
  • 說明:緩衝流對象bis和bos內部都定義了一個大小爲8192的字節數組,當調用read()或write()方法讀寫數據時,首先將讀寫的數據存入到定義好的字節數組,然後將字節數組的數據一次性地讀寫到文件中,這種方式與字節流的緩衝區類似,都對數據進行了緩衝,從而有效地提高了數據的讀寫效率。
  • 其實還可以將緩衝字節流和字節流緩衝區兩種方式結合起來,更好地提高文件讀寫效率。大家可以參看《Java案例:幾種方式拷貝文件的耗時比較》。

三、字符流

(一)字符流概述

除了字節流,JDK還提供了用於實現字符操作的字符流,同字節流一樣,字符流也有兩個抽象的頂級父類,分別是Reader和Writer。

1、字符輸入流Reader

在這裏插入圖片描述

2、字符輸出流Writer

在這裏插入圖片描述

(二)利用字符流讀文件

1、利用文件字符流逐個字符讀文件

  • 在當前包裏創建文本文件in.txt
    在這裏插入圖片描述
  • 創建Example2503
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * 功能:利用文件字符流逐個字符讀文件
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2503 {
    public static void main(String[] args) {
        // 聲明文件字符輸入流
        FileReader fr = null;
        try {
            // 創建文件字符輸入流
            fr = new FileReader("src/net/hw/lesson25/in.txt");

            // 循環讀取文件字符輸入流的數據
            int len = 0;
            while ((len = fr.read()) != -1) {
                System.out.print((char) len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 判斷文件字符輸入流是否爲空
            if (fr != null) {
                try {
                    // 關閉文件字符輸入流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 運行程序,查看結果
    在這裏插入圖片描述
  • 說明:有興趣的同學,可以添加代碼輸出文件拷貝耗費的時間。

2、利用文件字符流與字符流緩衝區讀取文件

  • 創建Example2504
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * 功能:利用文件字符流與字符流緩衝區讀取文件
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2504 {
    public static void main(String[] args) {
        // 聲明文件字符輸入流
        FileReader fr = null;
        try {
            // 創建文件字符輸入流
            fr = new FileReader("src/net/hw/lesson25/in.txt");

            // 定義字符數組作爲緩衝區
            char[] buffer = new char[1024];
            // 循環讀取文件字符輸入流的數據
            int len = 0;
            while ((len = fr.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, len));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 判斷文件字符輸入流是否爲空
            if (fr != null) {
                try {
                    // 關閉文件字符輸入流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 說明:在循環讀取文件字符輸入流中,不能直接打印字符緩衝區,要利用new String(buffer, 0, len)將字符數組充當的緩衝區轉換成字符串來輸出。
  • 運行程序,查看結果
    在這裏插入圖片描述

3、利用字符緩衝流逐個字符讀取文件

  • 創建Example2505
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * 功能:利用字符緩衝流逐個字符讀文件
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2505 {
    public static void main(String[] args) {
        // 聲明字符緩衝入流
        BufferedReader br = null;
        try {
            // 創建字符緩衝輸入流
            br = new BufferedReader(new FileReader("src/net/hw/lesson25/in.txt"));

            // 循環讀取字符緩衝輸入流的數據
            int len = 0;
            while ((len = br.read()) != -1) {
                System.out.print((char) len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 判斷字符緩衝輸入流是否爲空
            if (br != null) {
                try {
                    // 關閉字符緩衝輸入流
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 運行程序,查看結果
    在這裏插入圖片描述

4、課堂練習:利用緩衝字符流與字符流緩衝區讀取文件

在這裏插入圖片描述
在這裏插入圖片描述

(三)利用字符流寫文件

1、利用字符流非追加模式寫文件

非追加模式寫文件,如果文件不存在,就創建新文件再寫入內容;如果文件存在,先清空文件內容,然後在寫入新內容。

  • 創建Example2507
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 功能:利用字符流非追加模式寫文件
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2507 {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // 創建文件字符輸出流
            fw = new FileWriter("src/net/hw/lesson25/out.txt");

            // 將字符串寫入指定文件
            fw.write("十年磨劍意自閒,\n");
            fw.write("一朝出鞘氣沖天。\n");
            fw.write("男兒當有鴻鵠志,\n");
            fw.write("雄心萬丈跨羣山。\n");

            // 提示用戶數據寫入文件成功
            System.out.println("數據成功寫入文件!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 判斷文件字符流是否爲空
            if (fw != null) {
                try {
                    // 關閉文件字符輸出流
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 運行程序,查看結果
    在這裏插入圖片描述
  • 查看生成的輸出文件out.txt
    在這裏插入圖片描述
  • 說明:由於採用的是非追加模式寫文件,那麼再執行程序,你會發現輸出文件out.txt的內容依然如故,只有四行詩。

2、利用字符流追加模式寫文件

追加模式寫文件,如果文件不存在,就創建新文件再寫入內容;如果文件存在,在文件末尾追加新內容。

  • 創建Example2508
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 功能:利用字符流追加模式寫文件
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2508 {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // 創建文件字符輸出流,採用追加模式寫文件
            fw = new FileWriter("src/net/hw/lesson25/out.txt", true);

            // 將字符串寫入指定文件
            fw.write("滾滾紅塵意難安,\n");
            fw.write("欲作蠟炬兩頭燃。\n");
            fw.write("不羨平淡八十歲,\n");
            fw.write("但求絢爛一瞬間。\n");

            // 提示用戶數據寫入文件成功
            System.out.println("數據成功寫入文件!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 判斷文件字符流是否爲空
            if (fw != null) {
                try {
                    // 關閉文件字符輸出流
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在這裏插入圖片描述

  • 運行程序,查看結果
    在這裏插入圖片描述
  • 查看輸出文件out.txt
    在這裏插入圖片描述
  • 再次運行程序,你會發現輸出文件out.txt又添加四行。
    在這裏插入圖片描述

(四)利用字符流拷貝文件

1、文件拷貝思路

利用字符流拷貝文件,跟利用字節流拷貝文件思路完全類似,也有四種方式拷貝文件。是否使用字符緩衝流,是否使用字符流緩衝區,一搭配,共有四種處理方式。下面我只給出第四種方式:利用字符緩衝流與字符流緩衝區拷貝文件。

2、案例演示:利用字符緩衝流與字符流緩衝區拷貝文件

比如將當前包裏的in.txt文件拷貝到當前包裏的result.txt。

  • 創建Example2509
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.*;

/**
 * 功能:利用字符緩衝流與字符流緩衝區拷貝文件
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2509 {
    public static void main(String[] args) {
        // 聲明字符緩衝入流
        BufferedReader br = null;
        // 聲明字符緩衝輸出流
        BufferedWriter bw = null;
        try {
            // 創建字符緩衝輸入流
            br = new BufferedReader(new FileReader("src/net/hw/lesson25/in.txt"));
            // 創建字符緩衝輸出流
            bw = new BufferedWriter(new FileWriter("src/net/hw/lesson25/result.txt"));

            // 定義字符數組作爲緩衝區
            char[] buffer = new char[1024];
            // 循環讀取字符緩衝輸入流的數據
            int len = 0;
            while ((len = br.read(buffer)) != -1) {
                bw.write(buffer, 0, len);
            }

            // 提示用戶文件拷貝成功
            System.out.println("恭喜,文件拷貝成功!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 判斷字符緩衝輸入流是否爲空
            if (br != null) {
                try {
                    // 關閉字符緩衝輸入流
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 判斷字符緩衝輸出流是否爲空
            if (bw != null) {
                try {
                    // 關閉字符緩衝輸出流
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 運行程序,查看結果
    在這裏插入圖片描述
  • 查看拷貝生成的目標文件result.txt
    在這裏插入圖片描述

四、轉換流

1、轉換流概述

  • 在JDK中,提供了兩個類用於實現將字節流轉換爲字符流,它們分別是nputStreamReader和OutputStreamWriter。
  • InputStreamReader是Reader的子類,它可以將一個字節輸入流轉換成字符輸入流,方便直接讀取字符。
  • OutputStreamWriter是Writer的子類,它可以將一個字節輸出流轉換成字符輸出流,方便直接寫入字符。
    在這裏插入圖片描述
  • 將字節流轉換成字符流之後,往往再轉換成字符緩衝流,利用其提供的行讀取方法readLine()可以更好地提高讀寫效率。

可以參看《Java講課筆記24:字節流》裏的案例Example2403:行讀取鍵盤輸入的數據。

2、案例演示:利用轉換流和緩衝流實現文件拷貝

  • 創建Example2510
    在這裏插入圖片描述
package net.hw.lesson25;

import java.io.*;

/**
 * 功能:利用轉換流和緩衝流實現文件拷貝
 * 作者:華衛
 * 日期:2020年05月26日
 */
public class Example2510 {
    public static void main(String[] args) throws Exception {
        // 創建字符緩衝輸入流
        BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream("src/net/hw/lesson25/in.txt")));
        // 創建字符緩衝輸出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("src/net/hw/lesson25/target.txt")));

        // 定義文本行變量
        String nextLine = null;
        // 採用循環,行讀取文件
        while ((nextLine = br.readLine()) != null) {
            System.out.println(nextLine); // 輸出到控制檯
            bw.write(nextLine); // 寫入目標文件
            bw.newLine(); // 換行
        }

        // 關閉字符緩衝流
        br.close();
        bw.close();
    }
}
  • 運行程序,查看結果
    在這裏插入圖片描述
  • 查看拷貝生成的目標文件target.txt
    在這裏插入圖片描述
  • 注意:文件拷貝完成之後,必須關閉字符緩衝流。如果不關閉字符緩衝輸出流,那麼只在控制檯輸出了文件內容,但是目標文件target.txt卻是空的,數據還在緩衝流裏,當然可以使用flush()方法將數據刷新到文件裏,但是最好養成用完流對象之後關閉的好習慣。

五、課後作業

任務1、將兩個文本文件合併成一個新的文本文件

  • 創建文本文件in01.txt,隨意輸入一些內容
  • 創建文本文件in02.txt,隨意輸入一些內容
  • 利用文件字符流和字符緩衝流將in01.txt和in02.txt內容讀取出來寫入out.txt文件

任務2、將某個目錄下的全部文本文件合併生成一個文本文件

說明:完成這個任務,要用到下一講的File類,利用File類提供的方法可以獲取某個目錄下的全部文本文件名列表,然後遍歷讀取所有文件,將其全部寫入一個目標文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章