java基礎(24):轉換流、緩衝流

1. 轉換流

在學習字符流(FileReader、FileWriter)的時候,其中說若是須要指定編碼和緩衝區大小時,能夠在字節流的基礎上,構造一個InputStreamReader或者OutputStreamWriter,這又是什麼意思呢?數組

 

1.1 OutputStreamWriter

 

查閱OutputStreamWriterAPI介紹,OutputStreamWriter 是字符流通向字節流的橋樑:可以使用指定的字符編碼表,將要寫入流中的字符編碼成字節。它的做用的就是,將字符串按照指定的編碼表轉成字節,在使用字節流將這些字節寫出去。網絡

 

代碼演示:學習

public static void writeCN() throws Exception { //建立與文件關聯的字節輸出流對象
        FileOutputStream fos = new FileOutputStream("c:\\cn8.txt"); //建立能夠把字符轉成字節的轉換流對象,並指定編碼
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); //調用轉換流,把文字寫出去,實際上是寫到轉換流的緩衝區中
        osw.write("你好");//寫入緩衝區。
 osw.close(); }

OutputStreamWriter流對象,它到底如何把字符轉成字節輸出的呢?編碼

其實在OutputStreamWriter流中維護本身的緩衝區,當咱們調用OutputStreamWriter對象的write方法時,會拿着字符到指定的碼錶中進行查詢,把查到的字符編碼值轉成字節數存放到OutputStreamWriter緩衝區中。而後再調用刷新功能,或者關閉流,或者緩衝區存滿後會把緩衝區中的字節數據使用字節流寫到指定的文件中。spa

1.2 InputStreamReader

查閱InputStreamReaderAPI介紹,InputStreamReader 是字節流通向字符流的橋樑:它使用指定的字符編碼表讀取字節並將其解碼爲字符。它使用的字符集能夠由名稱指定或顯式給定,或者能夠接受平臺默認的字符集。3d

 

 

代碼演示code

 

public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { //演示字節轉字符流的轉換流
 readCN(); } public static void readCN() throws IOException{ //建立讀取文件的字節流對象
        InputStream in = new FileInputStream("c:\\cn8.txt"); //建立轉換流對象 //InputStreamReader isr = new InputStreamReader(in);這樣建立對象,會用本地默認碼錶讀取,將會發生錯誤解碼的錯誤
        InputStreamReader isr = new InputStreamReader(in,"utf-8"); //使用轉換流去讀字節流中的字節
        int ch = 0; while((ch = isr.read())!=-1){ System.out.println((char)ch); } //關閉流
 isr.close(); } }

注意:在讀取指定的編碼的文件時,必定要指定編碼格式,不然就會發生解碼錯誤,而發生亂碼現象。對象

1.3 轉換流和子類區別

發現有以下繼承關係:blog

OutputStreamWriter:繼承

  |--FileWriter:

InputStreamReader:

  |--FileReader;

 

父類和子類的功能有什麼區別呢?

OutputStreamWriterInputStreamReader是字符和字節的橋樑:也能夠稱之爲字符轉換流。字符轉換流原理:字節流+編碼表。

FileWriterFileReader:做爲子類,僅做爲操做字符文件的便捷類存在。當操做的字符文件,使用的是默認編碼表時能夠不用父類,而直接用子類就完成操做了,簡化了代碼。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默認字符集。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。

FileReader fr = new FileReader("a.txt");

這三句代碼的功能是同樣的,其中第三句最爲便捷。

注意:一旦要指定其餘編碼時,絕對不能用子類,必須使用字符轉換流。何時用子類呢?

條件:

1、操做的是文件。2、使用默認編碼。

總結:

字節--->字符 : 看不懂的--->看的懂的。  須要讀。輸入流。 InputStreamReader

字符--->字節 : 看的懂的--->看不懂的。  須要寫。輸出流。 OutputStreamWriter

2. 緩衝流

在咱們學習字節流與字符流的時候,你們都進行過讀取文件中數據的操做,讀取數據量大的文件時,讀取的速度會很慢,很影響咱們程序的效率,那麼,我想提升速度,怎麼辦?

Java中提升了一套緩衝流,它的存在,可提升IO流的讀寫速度

緩衝流,根據流的分類分類字節緩衝流與字符緩衝流。

2.1 字節緩衝流

字節緩衝流根據流的方向,共有2

寫入數據到流中,字節緩衝輸出流 BufferedOutputStream

讀取流中的數據,字節緩衝輸入流 BufferedInputStream

 

它們的內部都包含了一個緩衝區,經過緩衝區讀寫,就能夠提升了IO流的讀寫速度

2.1.1 字節緩衝輸出流BufferedOutputStream

經過字節緩衝流,進行文件的讀寫操做 寫數據到文件的操做  

構造方法

public BufferedOutputStream(OutputStream out)建立一個新的緩衝輸出流,以將數據寫入指定的底層輸出流。 

public class BufferedOutputStreamDemo01 { public static void main(String[] args) throws IOException { //寫數據到文件的方法
 write(); } /* * 寫數據到文件的方法 * 1,建立流 * 2,寫數據 * 3,關閉流 */
    private static void write() throws IOException { //建立基本的字節輸出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt"); //使用高效的流,把基本的流進行封裝,實現速度的提高
        BufferedOutputStream out = new BufferedOutputStream(fileOut); //2,寫數據
        out.write("hello".getBytes()); //3,關閉流
 out.close(); } }

2.1.2 字節緩衝輸入流 BufferedInputStream

剛剛咱們學習了輸出流實現了向文件中寫數據的操做,那麼,如今咱們完成讀取文件中數據的操做

構造方法

public BufferedInputStream(InputStream in) 

/* * 從文件中讀取數據 * 1,建立緩衝流對象 * 2,讀數據,打印 * 3,關閉  */
private static void read() throws IOException { //1,建立緩衝流對象
        FileInputStream fileIn = new FileInputStream("abc.txt"); //把基本的流包裝成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn); //2,讀數據
        int ch = -1; while ( (ch = in.read()) != -1 ) { //打印
            System.out.print((char)ch); } //3,關閉
 in.close(); }

2.1.3 使用基本的流與高效的流完成複製文件

咱們一直在說,高效的流速度快並高效,怎麼體現呢?須要經過一個複製文件耗時的比較過程,來體驗一下高效流帶來的快感。

/* * 需求:將d:\\test.avi文件進行復制 * 採用4種方式複製 * 方式1: 採用基本的流,一次一個字節的方式複製 共耗時 224613毫秒 * 方式2: 採用基本的流,一個多個字節的方式賦值 共耗時 327毫秒 * 方式3: 採用高效的流,一次一個字節的方式複製 共耗時 2047毫秒 * 方式4: 採用高效的流,一個多個字節的方式賦值 共耗時 96毫秒 * * 數據源: d:\\test.avi * 目的地1: d:\\copy1.avi * 目的地2: d:\\copy2.avi * 目的地3: d:\\copy3.avi * 目的地4: d:\\copy4.avi * * 實現的步驟: * 1,指定數據源 * 2,指定目的地 * 3,讀數據 * 4,寫數據 * 5,關閉流 * */
public class CopyAVI { public static void main(String[] args) throws IOException { //開始計時
        long start = System.currentTimeMillis(); //方式1: 採用基本的流,一次一個字節的方式複製 //method1("d:\\test.avi", "d:\\copy1.avi"); //方式2: 採用基本的流,一個多個字節的方式賦值 //method2("d:\\test.avi", "d:\\copy2.avi"); //方式3: 採用高效的流,一次一個字節的方式複製 //method3("d:\\test.avi", "d:\\copy3.avi"); //方式4: 採用高效的流,一個多個字節的方式賦值
        method4("d:\\test.avi", "d:\\copy4.avi"); //結束計時
        long end = System.currentTimeMillis(); //打印耗時多少毫秒
        System.out.println("共耗時 " +(end - start)+ "毫秒"); } //方式4: 採用高效的流,一個多個字節的方式賦值
    private static void method4(String src, String dest) throws IOException { //1,指定數據源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,讀數據
        byte[] buffer = new byte[1024]; int len = -1; while ( (len = in.read(buffer)) != -1) { //4,寫數據
            out.write(buffer, 0, len); } //5,關閉流
 in.close(); out.close(); } //方式3: 採用高效的流,一次一個字節的方式複製
    private static void method3(String src, String dest) throws IOException { //1,指定數據源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,讀數據
        int ch = -1; while ((ch=in.read()) != -1) { //4,寫數據
 out.write(ch); } //5,關閉流
 in.close(); out.close(); } //方式2: 採用基本的流,一個多個字節的方式賦值
    private static void method2(String src, String dest) throws IOException { //1,指定數據源
        FileInputStream in = new FileInputStream(src); //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest); //3,讀數據
        byte[] buffer = new byte[1024]; int len = -1; while ( (len=in.read(buffer)) != -1) { //4,寫數據
            out.write(buffer, 0, len); } //5,關閉流
 in.close(); out.close(); } //方式1: 採用基本的流,一次一個字節的方式複製
    private static void method1(String src, String dest) throws IOException { //1,指定數據源
        FileInputStream in = new FileInputStream(src); //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest); //3,讀數據
        int ch = -1; while (( ch=in.read()) != -1) { //4,寫數據
 out.write(ch); } //5,關閉流
 in.close(); out.close(); } }

2.2 字符緩衝流

字符緩衝輸入流 BufferedReader

字符緩衝輸出流 BufferedWriter

完成文本數據的高效的寫入與讀取的操做

2.2.1 字符緩衝輸出流 BufferedWriter

將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入

方法:

void newLine() 根據當前的系統,寫入一個換行符

/* * BufferedWriter 字符緩衝輸出流 * 方法 * public void newLine()寫入一個行分隔符 * * 需求: 經過緩衝輸出流寫入數據到文件 * 分析: * 1,建立流對象 * 2,寫數據 * 3,關閉流 * */
public class BufferedWriterDemo { public static void main(String[] args) throws IOException { //建立流 //基本字符輸出流
        FileWriter fileOut = new FileWriter("file.txt"); //把基本的流進行包裝
        BufferedWriter out = new BufferedWriter(fileOut); //2,寫數據
        for (int i=0; i<5; i++) { out.write("hello"); out.newLine(); } //3,關閉流
 out.close(); } }

2.2.2 字符緩衝輸入流 BufferedReader

從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。

方法

public String readLine() 讀取一個文本行包含該行內容的字符串,不包含任何行終止符,若是已到達流末尾,則返回 null

/* * BufferedReader 字符緩衝輸入流 * * 方法: * String readLine() * 需求:從文件中讀取數據,並顯示數據 */
public class BufferedReaderDemo { public static void main(String[] args) throws IOException { //1,建立流
        BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,讀數據 //一次一個字符 //一次一個字符數組 //一次讀取文本中一行的字符串內容
        String line = null; while( (line = in.readLine()) != null ){ System.out.println(line); } //3,關閉流
 in.close(); } }

2.2.3 使用字符緩衝流完成文本文件的複製

剛剛咱們學習完了緩衝流,如今咱們就使用字符緩衝流的特有功能,完成文本文件的複製

/* * 採用高效的字符緩衝流,完成文本文件的賦值 * * 數據源: file.txt * 目的地: copyFile.txt * * 分析: * 1,指定數據源, 是數據源中讀數據,採用輸入流 * 2,指定目的地,是把數據寫入目的地,採用輸出流 * 3,讀數據 * 4,寫數據 * 5,關閉流 */
public class CopyTextFile { public static void main(String[] args) throws IOException { //1,指定數據源, 是數據源中讀數據,採用輸入流
        BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,指定目的地,是把數據寫入目的地,採用輸出流
        BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt")); //3,讀數據
        String line = null; while ( (line = in.readLine()) != null ) { //4,寫數據
 out.write(line); //寫入換行符號
 out.newLine(); } //5,關閉流
 out.close(); in.close(); } }

3. 流的操做規律

IO流中對象不少,解決問題(處理設備上的數據時)到底該用哪一個對象呢?  

IO流進行了規律的總結(四個明確)

明確一:要操做的數據是數據源仍是數據目的。

  源:InputStream    Reader

  目的:OutputStream Writer

先根據需求明確要讀,仍是要寫。

 

明確二:要操做的數據是字節仍是文本呢?

源:

  字節:InputStream

  文本:Reader

目的:

  字節:OutputStream

  文本:Writer

已經明確到了具體的體系上。

 

明確三:明確數據所在的具體設備。

源設備:

  硬盤:文件  File開頭。

  內存:數組,字符串。

  鍵盤:System.in;

  網絡:Socket

目的設備:

  硬盤:文件  File開頭。

  內存:數組,字符串。

  屏幕:System.out

  網絡:Socket

徹底能夠明確具體要使用哪一個流對象。

 

l 明確四:是否須要額外功能呢?

額外功能:

  轉換嗎?轉換流。InputStreamReader OutputStreamWriter

  高效嗎?緩衝區對象。BufferedXXX

InputStream

       FileInputStream

       BufferedInputStream

OuputStream

  FileOutputStream

  BufferedOuputStream

Writer

  OutputStreamWriter

  FileWriter

  BufferedWriter

Reader

  InputStreamReader

  FileReader

  BufferedReader

相關文章
相關標籤/搜索