Java IO之轉(zhuǎn)換流和緩存流

1 轉(zhuǎn)換流

??在學(xué)習(xí)字符流(FileReader、FileWriter)的時(shí)候,其中說(shuō)如果需要指定編碼和緩沖區(qū)大小時(shí),可以在字節(jié)流的基礎(chǔ)上,構(gòu)造一個(gè)InputStreamReader或者OutputStreamWriter,這又是什么意思呢?

1.1 OutputStreamWriter類(lèi)

??查閱OutputStreamWriter的API介紹,OutputStreamWriter 是字符流通向字節(jié)流的橋梁:可使用指定的字符編碼表,將要寫(xiě)入流中的字符編碼成字節(jié)。它的作用的就是,將字符串按照指定的編碼表轉(zhuǎn)成字節(jié),在使用字節(jié)流將這些字節(jié)寫(xiě)出去。

TestDemo.java

package com.qtw.api;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        //創(chuàng)建與文件關(guān)聯(lián)的字節(jié)輸出流對(duì)象
        FileOutputStream fos = new FileOutputStream("e:\\test\\b.txt");
        //創(chuàng)建可以把字符轉(zhuǎn)成字節(jié)的轉(zhuǎn)換流對(duì)象,并指定編碼
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
        //調(diào)用轉(zhuǎn)換流,把文字寫(xiě)出去,其實(shí)是寫(xiě)到轉(zhuǎn)換流的緩沖區(qū)中
        osw.write("你好");//寫(xiě)入緩沖區(qū)。
        osw.close();
        //gbk編碼,一個(gè)漢字對(duì)應(yīng)2個(gè)字節(jié);utf-8編碼,一個(gè)漢字對(duì)應(yīng)3個(gè)字節(jié)
    }
}

??OutputStreamWriter流對(duì)象,它到底如何把字符轉(zhuǎn)成字節(jié)輸出的呢?
??其實(shí)在OutputStreamWriter流中維護(hù)自己的緩沖區(qū),當(dāng)我們調(diào)用OutputStreamWriter對(duì)象的write方法時(shí),會(huì)拿著字符到指定的碼表中進(jìn)行查詢(xún),把查到的字符編碼值轉(zhuǎn)成字節(jié)數(shù)存放到OutputStreamWriter緩沖區(qū)中。然后再調(diào)用刷新功能,或者關(guān)閉流,或者緩沖區(qū)存滿后會(huì)把緩沖區(qū)中的字節(jié)數(shù)據(jù)使用字節(jié)流寫(xiě)到指定的文件中。

1.2 InputStreamReader類(lèi)

??查閱InputStreamReader的API介紹,InputStreamReader 是字節(jié)流通向字符流的橋梁:它使用指定的字符編碼表讀取字節(jié)并將其解碼為字符。它使用的字符集可以由名稱(chēng)指定或顯式給定,或者可以接受平臺(tái)默認(rèn)的字符集。

TestDemo.java

package com.qtw.api;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStreamReader;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        //創(chuàng)建讀取文件的字節(jié)流對(duì)象
        FileInputStream in = new FileInputStream("e:\\test\\a.txt");
        //創(chuàng)建轉(zhuǎn)換流對(duì)象
        //InputStreamReader isr = new InputStreamReader(in);這樣創(chuàng)建對(duì)象,會(huì)用本地默認(rèn)碼表讀取,將會(huì)發(fā)生錯(cuò)誤解碼的錯(cuò)誤
        InputStreamReader isr = new InputStreamReader(in,"utf-8");
        //使用轉(zhuǎn)換流去讀字節(jié)流中的字節(jié)
        int ch = 0;
        while((ch = isr.read())!=-1){
            System.out.println((char)ch);
        }
        //關(guān)閉流
        isr.close();
    }
}

注意:在讀取指定的編碼的文件時(shí),一定要指定編碼格式,否則就會(huì)發(fā)生解碼錯(cuò)誤,而發(fā)生亂碼現(xiàn)象

1.3 轉(zhuǎn)換流和子類(lèi)區(qū)別

發(fā)現(xiàn)有如下繼承關(guān)系:

OutputStreamWriter:
    |--FileWriter:
InputStreamReader:
    |--FileReader;

父類(lèi)和子類(lèi)的功能有什么區(qū)別呢?
??OutputStreamWriter和InputStreamReader是字符和字節(jié)的橋梁:也可以稱(chēng)之為字符轉(zhuǎn)換流。字符轉(zhuǎn)換流原理:字節(jié)流+編碼表。
??FileWriter和FileReader:作為子類(lèi),僅作為操作字符文件的便捷類(lèi)存在。當(dāng)操作的字符文件,使用的是默認(rèn)編碼表時(shí)可以不用父類(lèi),而直接用子類(lèi)就完成操作了,簡(jiǎn)化了代碼。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默認(rèn)字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
//這三句代碼的功能是一樣的,其中第三句最為便捷。

注意:一旦要指定其他編碼時(shí),絕對(duì)不能用子類(lèi),必須使用字符轉(zhuǎn)換流。

2 緩沖流

??在我們學(xué)習(xí)字節(jié)流與字符流的時(shí)候,大家都進(jìn)行過(guò)讀取文件中數(shù)據(jù)的操作,讀取數(shù)據(jù)量大的文件時(shí),讀取的速度會(huì)很慢,很影響我們程序的效率,那么,我想提高速度,怎么辦?Java中提高了一套緩沖流,它的存在,可提高IO流的讀寫(xiě)速度。緩沖流,根據(jù)流的分類(lèi)分為字節(jié)緩沖流與字符緩沖流。

2.1 字節(jié)緩沖流

字節(jié)緩沖流根據(jù)流的方向,共有2個(gè)

  1. 寫(xiě)入數(shù)據(jù)到流中,字節(jié)緩沖輸出流 BufferedOutputStream
  2. 讀取流中的數(shù)據(jù),字節(jié)緩沖輸入流 BufferedInputStream

它們的內(nèi)部都包含了一個(gè)緩沖區(qū),通過(guò)緩沖區(qū)讀寫(xiě),就可以提高了IO流的讀寫(xiě)速度

2.1.1 字節(jié)緩沖輸出流BufferedOutputStream

通過(guò)字節(jié)緩沖流,進(jìn)行文件的讀寫(xiě)操作 寫(xiě)數(shù)據(jù)到文件的操作
構(gòu)造方法

public BufferedOutputStream(OutputStream out)

TestDemo.java

package com.qtw.api;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedOutputStream;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        /*
         * 寫(xiě)數(shù)據(jù)到文件的方法
         * 1,創(chuàng)建流
         * 2,寫(xiě)數(shù)據(jù)
         * 3,關(guān)閉流
         */

        //創(chuàng)建基本的字節(jié)輸出流
        FileOutputStream fileOut = new FileOutputStream("e:\\test\\abc.txt");
        //使用高效的流,把基本的流進(jìn)行封裝,實(shí)現(xiàn)速度的提升
        BufferedOutputStream out = new BufferedOutputStream(fileOut);
        //2,寫(xiě)數(shù)據(jù)
        out.write("hello".getBytes());
        //3,關(guān)閉流
        out.close();
    }
}

2.1.2 字節(jié)緩沖輸入流 BufferedInputStream

讀取文件中數(shù)據(jù)的操作
構(gòu)造方法

public BufferedInputStream(InputStream in) 

TestDemo.java

package com.qtw.api;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.BufferedInputStream;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        /*
         * 從文件中讀取數(shù)據(jù)
         * 1,創(chuàng)建緩沖流對(duì)象
         * 2,讀數(shù)據(jù),打印
         * 3,關(guān)閉
         */
        //1,創(chuàng)建緩沖流對(duì)象
        FileInputStream fileIn = new FileInputStream("e:\\test\\abc.txt");
        //把基本的流包裝成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn);
        //2,讀數(shù)據(jù)
        int ch = -1;
        while ( (ch = in.read()) != -1 ) {
            //打印
            System.out.print((char)ch);
        }
        //3,關(guān)閉
        in.close();
    }
}

2.1.3 使用基本的流與高效的流完成復(fù)制文件

??我們一直在說(shuō),高效的流速度快并高效,怎么體現(xiàn)呢?需要通過(guò)一個(gè)復(fù)制文件耗時(shí)的比較過(guò)程,來(lái)體驗(yàn)一下高效流帶來(lái)的快感。
TestDemo.java

package com.qtw.api;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

public class TestDemo {
    /*
     * 需求:將d:\\test.avi文件進(jìn)行復(fù)制
     *      采用4種方式復(fù)制
     *      方式1: 采用基本的流,一次一個(gè)字節(jié)的方式復(fù)制 共耗時(shí) 317304毫秒
     *      方式2: 采用基本的流,一個(gè)多個(gè)字節(jié)的方式賦值 共耗時(shí)     427毫秒
     *      方式3: 采用高效的流,一次一個(gè)字節(jié)的方式復(fù)制 共耗時(shí)    568毫秒
     *      方式4: 采用高效的流,一個(gè)多個(gè)字節(jié)的方式賦值 共耗時(shí)      68毫秒
     *
     * 數(shù)據(jù)源: d:\\test.avi
     * 目的地1: d:\\copy1.avi
     * 目的地2: d:\\copy2.avi
     * 目的地3: d:\\copy3.avi
     * 目的地4: d:\\copy4.avi
     *
     * 實(shí)現(xiàn)的步驟:
     *  1,指定數(shù)據(jù)源
     *  2,指定目的地
     *  3,讀數(shù)據(jù)
     *  4,寫(xiě)數(shù)據(jù)
     *  5,關(guān)閉流
     *
     */

    public static void main(String[] args) throws IOException {
        //開(kāi)始計(jì)時(shí)
        long start = System.currentTimeMillis();
        //方式1: 采用基本的流,一次一個(gè)字節(jié)的方式復(fù)制
        //method1("e:\\test\\dd.avi", "e:\\test\\dx.avi");
        //方式2: 采用基本的流,一個(gè)多個(gè)字節(jié)的方式賦值
        //method2("e:\\test\\dd.avi", "e:\\test\\dx.avi");
        //方式3: 采用高效的流,一次一個(gè)字節(jié)的方式復(fù)制
        //method3("e:\\test\\dd.avi", "e:\\test\\dx.avi");
        //方式4: 采用高效的流,一個(gè)多個(gè)字節(jié)的方式賦值
        method4("e:\\test\\dd.avi", "e:\\test\\dx.avi");

        //結(jié)束計(jì)時(shí)
        long end = System.currentTimeMillis();
        //打印耗時(shí)多少毫秒
        System.out.println("共耗時(shí) " +(end - start)+ "毫秒");

    }

    //方式4: 采用高效的流,一個(gè)多個(gè)字節(jié)的方式賦值
    private static void method4(String src, String dest) throws IOException {
        //1,指定數(shù)據(jù)源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
        //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
        //3,讀數(shù)據(jù)
        byte[] buffer = new byte[1024];
        int len = -1;
        while ( (len = in.read(buffer)) != -1) {
            //4,寫(xiě)數(shù)據(jù)
            out.write(buffer, 0, len);
        }
        //5,關(guān)閉流
        in.close();
        out.close();
    }

    //方式3: 采用高效的流,一次一個(gè)字節(jié)的方式復(fù)制
    private static void method3(String src, String dest) throws IOException {
        //1,指定數(shù)據(jù)源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
        //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
        //3,讀數(shù)據(jù)
        int ch = -1;
        while ((ch=in.read()) != -1) {
            //4,寫(xiě)數(shù)據(jù)
            out.write(ch);
        }
        //5,關(guān)閉流
        in.close();
        out.close();
    }

    //方式2: 采用基本的流,一個(gè)多個(gè)字節(jié)的方式賦值
    private static void method2(String src, String dest) throws IOException {
        //1,指定數(shù)據(jù)源
        FileInputStream in = new FileInputStream(src);
        //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest);
        //3,讀數(shù)據(jù)
        byte[] buffer = new byte[1024];
        int len = -1;
        while ( (len=in.read(buffer)) != -1) {
            //4,寫(xiě)數(shù)據(jù)
            out.write(buffer, 0, len);
        }
        //5,關(guān)閉流
        in.close();
        out.close();
    }

    //方式1: 采用基本的流,一次一個(gè)字節(jié)的方式復(fù)制
    private static void method1(String src, String dest) throws IOException {
        //1,指定數(shù)據(jù)源
        FileInputStream in = new FileInputStream(src);
        //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest);
        //3,讀數(shù)據(jù)
        int ch = -1;
        while (( ch=in.read()) != -1) {
            //4,寫(xiě)數(shù)據(jù)
            out.write(ch);
        }
        //5,關(guān)閉流
        in.close();
        out.close();
    }
}

2.2 字符緩沖流

字符緩沖輸入流 BufferedReader
字符緩沖輸出流 BufferedWriter
完成文本數(shù)據(jù)的高效的寫(xiě)入與讀取的操作

2.2.1 字符緩沖輸出流 BufferedWriter

將文本寫(xiě)入字符輸出流,緩沖各個(gè)字符,從而提供單個(gè)字符、數(shù)組和字符串的高效寫(xiě)入。

void newLine() 根據(jù)當(dāng)前的系統(tǒng),寫(xiě)入一個(gè)換行符

TestDemo.java

package com.qtw.api;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        /*
         * BufferedWriter 字符緩沖輸出流
         * 方法
         *  public void newLine()寫(xiě)入一個(gè)行分隔符
         *
         * 需求: 通過(guò)緩沖輸出流寫(xiě)入數(shù)據(jù)到文件
         * 分析:
         *  1,創(chuàng)建流對(duì)象
         *  2,寫(xiě)數(shù)據(jù)
         *  3,關(guān)閉流
         *
         */
        //創(chuàng)建流
        //基本字符輸出流
        FileWriter fileOut = new FileWriter("e:\\test\\file.txt");
        //把基本的流進(jìn)行包裝
        BufferedWriter out = new BufferedWriter(fileOut);
        //2,寫(xiě)數(shù)據(jù)
        for (int i=0; i<5; i++) {
            out.write("hello");
            out.newLine();
        }
        //3,關(guān)閉流
        out.close();
    }
}

2.2.2 字符緩沖輸入流 BufferedReader

從字符輸入流中讀取文本,緩沖各個(gè)字符,從而實(shí)現(xiàn)字符、數(shù)組和行的高效讀取。

public String readLine() 讀取一個(gè)文本行,包含該行內(nèi)容的字符串,不包含任何行終止符,如果已到達(dá)流末尾,則返回 null

TestDemo.java

package com.qtw.api;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        /*
         * BufferedReader 字符緩沖輸入流
         *
         * 方法:
         *  String readLine()
         * 需求:從文件中讀取數(shù)據(jù),并顯示數(shù)據(jù)
         */
        //1,創(chuàng)建流
        BufferedReader in = new BufferedReader(new FileReader("e:\\test\\file.txt"));
        //2,讀數(shù)據(jù)
        //一次一個(gè)字符
        //一次一個(gè)字符數(shù)組
        //一次讀取文本中一行的字符串內(nèi)容
        String line = null;
        while( (line = in.readLine()) != null ){
            System.out.println(line);
        }
        //3,關(guān)閉流
        in.close();
    }
}

2.2.3 使用字符緩沖流完成文本文件的復(fù)制

剛剛我們學(xué)習(xí)完了緩沖流,現(xiàn)在我們就使用字符緩沖流的特有功能,完成文本文件的復(fù)制
TestDemo.java

package com.qtw.api;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;

public class TestDemo {
    public static void main(String[] args) throws IOException {
        /*
         * 采用高效的字符緩沖流,完成文本文件的賦值
         *
         * 數(shù)據(jù)源: file.txt
         * 目的地: copyFile.txt
         *
         * 分析:
         *  1,指定數(shù)據(jù)源, 是數(shù)據(jù)源中讀數(shù)據(jù),采用輸入流
         *  2,指定目的地,是把數(shù)據(jù)寫(xiě)入目的地,采用輸出流
         *  3,讀數(shù)據(jù)
         *  4,寫(xiě)數(shù)據(jù)
         *  5,關(guān)閉流
         */

        //1,指定數(shù)據(jù)源, 是數(shù)據(jù)源中讀數(shù)據(jù),采用輸入流
        BufferedReader in = new BufferedReader(new FileReader("e:\\test\\file.txt"));
        //2,指定目的地,是把數(shù)據(jù)寫(xiě)入目的地,采用輸出流
        BufferedWriter out = new BufferedWriter(new FileWriter("e:\\test\\copyFile.txt"));
        //3,讀數(shù)據(jù)
        String line = null;
        while ( (line = in.readLine()) != null ) {
            //4,寫(xiě)數(shù)據(jù)
            out.write(line);
            //寫(xiě)入換行符號(hào)
            out.newLine();
        }
        //5,關(guān)閉流
        out.close();
        in.close();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容