Java字節流與字符流


九、字節流與字符流

9.1 IO的分類

<段落>根據數據的流向分為:輸入流和輸出流。
  • 輸入流 :把數據從其他設備上讀取到內存中的流。
  • 輸出流 :把數據從內存 中寫出到其他設備上的流。
        數據的類型分為:字節流和字符流。
  • 字節流 :以字節為單位,讀寫數據的流。
  • 字符流 :以字符為單位,讀寫數據的流。
                                           
                                           頂級父類表:
  輸入流 輸出流
字節流 字節輸入流 InputStream 字節輸出流 OutputStream
字符流 字符輸入流 Reader 字符輸出流Writer

  9.2字節流輸出流

      9.2.1  概述:

                   一切文件數據都是以二進制數字的形式保存,我們要時刻明確,無論使用什么樣的流對象,底層傳輸始終為二進制數據。

      9.2.2 字節輸出流的構造方法:  

OutputStream有很多子類,我們從最簡單的一個子類開始。

java.io.FileOutputStream類是文件輸出流,用於將數據寫出到文件。

                   構造方法

public FileOutputStream(File file):創建文件輸出流以寫入由指定的 File對象表示的文件。notes: 在進行構造的時候,如果父目錄不存在,則會報錯,在創建時 父目錄存在,但是文件不存在,則會幫你創建。

public FileOutputStream(String name): 創建文件輸出流以指定的名稱寫入文件

notes:

當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有這個文件,會創建該文件。如果有這個文件,會清空這個文件的數據。

                            
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        // 創建 File 對象
        File file = new File("a.txt");
        // 創建文件輸出流對象
        FileOutputStream fos = new FileOutputStream(file);
         // 使用文件 名稱創建 輸出流對象
        FileOutputStream fos1 = new FileOutputStream("a.txt");
        fos.close();
        fos1.close();
    }
 
 
 

        9.2.3字節輸出流的基本共性方法:

               java.io.OutputStream抽象類是表示字節輸出流的所有類的超類,將指定的字節信息寫出到目的地。它定義了字節輸出流的基本共性功能方法。

  •  

    public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
    public void flush() :刷新此輸出流並強制任何緩沖的輸出字節被寫出。
    public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。
    public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。
    public abstract void write(int b) :將指定的字節輸出流。

     

tipps:

close方法,當完成流的操作時,必須調用此方法,釋放系統資源。

                        
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException{
        // 在 寫的時候 是 將原來的刪除 然后再去 寫
        FileOutputStream fos = new FileOutputStream("fos.txt");
        // 寫 數據
        fos.write(97);
        fos.write(98);
        //根據 字節數組 寫數據
        byte[] b = {'1','2','3','4'};
        fos.write(b);
        // 將指定 段 數據寫入
        // write(byte[] b, int off, int len) ,每次寫出從off索引開始,len個字節
        fos.write(b,0,2);
        // 關閉
        fos.close();
    }
-->輸出結果:
        當沒有fos.txt文件時,寫入ab123412
        有則將其覆蓋
 
 
                    tips:
                            1.雖然 參數 為 int 類型 四個字節 但是 只會保留一個字節的信息寫出
                            2.流操作完畢后,必須釋放系統資源,調用close方法

        數據追加續寫: (只需要在 原來的 構造方法 后再加 一個參數 ,true表示 續寫,false 表示清空數據)

        每次都會 清空目標文件中的數據,如何保留目標文件中數據,還能繼續添加數據
        構造方法:
  • public FileOutputStream(File file, boolean append): 創建文件輸出流以寫入由指定的 File對象表示的文件。

  • public FileOutputStream(String name, boolean append): 創建文件輸出流以指定的名稱寫入文件。

        寫出換行:
                    \r 回車符  回到一行的開頭               \n 換行符另起一行
                    系統中
                    Windows 系統里 換行符合為  \r\n   
                    Unix系統里 沒行結尾只有 換行  即  \n;
                    Mac系統里,每行結尾是 回車,即\r 。從 Mac OS X開始與Linux 統一。 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException{
        // 在 寫的時候 是 將原來的刪除 然后再去 寫
        FileOutputStream fos = new FileOutputStream("fos.txt");
        // 寫 數據
        fos.write(97);
        fos.write(98);
        fos.write("\r\n".getBytes());
        //根據 字節數組 寫數據
        byte[] b = {'1','2','3','4'};
        fos.write(b);
        // 將指定 段 數據寫入
        fos.write(b,0,2);
        // 關閉
        fos.close();
    }
結果是:
    ab
    123412
 
 

9.3字節輸入流 InputStream

    java.io.InputStream抽象類是表示字節輸入流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸入流的基本共性功能方法。

  • public void close() :關閉此輸入流並釋放與此流相關聯的任何系統資源。

  • public abstract int read(): 從輸入流讀取數據的下一個字節。

  • public int read(byte[] b): 從輸入流中讀取一些字節數,並將它們存儲到字節數組 b中 。

tips:

close方法,當完成流的操作時,必須調用此方法,釋放系統資源。

        9.3.1 構造方法

                

java.io.FileInputStream類是文件輸入流,從文件中讀取字節

構造方法

FileInputStream(File file): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。
FileInputStream(String name): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名 name命名。

當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有該文件,會拋出FileNotFoundException

<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("a.txt");
        // 通過構造方法 創建 輸入流對象
        FileInputStream fis = new FileInputStream(file);
        FileInputStream fis1 = new FileInputStream("a.txt");
    }
 
 

            9.3.2 方法

                    1.讀取字節:read方法,每次可以讀取一個字節的數據,提升為int類型,當讀取到文件末尾的時候 則會返回 -1 。
                    可以根據 -1 來判斷是否到達文件末尾:
                    
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        File file = new File("fos.txt");
        // 通過構造方法 創建 輸入流對象
        FileInputStream fis = new FileInputStream(file);
        FileInputStream fis1 = new FileInputStream("fos.txt");
        // 提升成 int 類型
        int read = fis.read();
        System.out.println("read = " + read); // 如果不轉換成 char 類型 則是97 轉成char類型則是 a
        int read1 = fis.read();
        System.out.println("read = " + read1);
        int read2 = fis.read();
        System.out.println("read = " + read2);
        int read3 = fis.read();
        System.out.println("read = " + read3);
        // 讀取到文件末尾就返回 -1
        fis.close();
        fis1.close();
    }
 
 
                    2.對循環進行改進 使用while 循環
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        // 創建文件對象
        File file = new File("fos.txt");
        // 創建 輸入流對象
        FileInputStream fis = new FileInputStream(file);
        // 通過while 循環 當 b != -1 時 退出
        int b;
        while ((b = fis.read()) != -1) {
            System.out.println("b = " + (char) b);
        }
        // 關閉流對象
        fis.close();
    }
 
 
                    tips:
                            1.雖然讀取了一個字節,但是會自動提升 為 int 類型 
                            2. 流操作完畢后,必須釋放系統資源, 調用close方法
                
                3.使用字節數組讀取 : read(byte[]  b), 每次讀取b個長度的字節到數組中,返回讀取到的有效字節個數 讀取到末尾時 返回 -1
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException{
       // 使用文件名稱創建流對象.
        FileInputStream fis = new FileInputStream("read.txt"); // 文件中為abcde
       // 定義變量,作為有效個數
        int len 
        // 定義字節數組,作為裝字節數據的容器   
        byte[] b = new byte[2];
        // 循環讀取
        while (( len= fis.read(b))!=-1) {
            // 每次讀取后,把數組變成字符串打印
            System.out.println(new String(b));
        }
  // 關閉資源
        fis.close();
    }
 
 
                tips:
                        使用數組進行讀取,每次讀取多個字節,減少系統見4的IO操作的次數,從而 提高了讀寫的效率,建議開發中使用

                9.3.3視頻的復制

                    從已有的文件中讀取字節,將該字節寫出到另一個文件中
                        
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\111\\shipin.flv");
        // 創建 輸入流 將文件讀入 到內存中
        FileInputStream fis = new FileInputStream(file);
        // 創建輸出流 將數據從內存寫入到 文件中
        FileOutputStream fos = new FileOutputStream("D:\\2222\\flower.flv");
        int len;
        byte[] b = new byte[1024];
        // 循環讀取
        while ((len = fis.read(b)) != -1) {
            // 寫數據
            fos.write(b,0,len);
        }
        fos.close();
        fis.close();
    }
 
 
                        notes:
                                流關閉原則:    先開后關,后開先關

                9.3.4字節緩沖流包裝

                                構造方法:
                            public BufferInputStream(InputStream in): 創建一個新的緩沖輸入流
                            public BufferOutputStream(OutputStream out):創建一個新緩沖輸出流
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws FileNotFoundException {
        // 創建 字節緩沖輸入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        // 創建 字節緩沖輸出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
    }
 
 
                            實現一個復制視頻的操作,聯系 BufferInputStream 和 BufferOutputStream
                         
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        // 復制一份視頻 用BuffOutputStream
        // 創建一個 輸入流對象
        long start = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/福利贈送.flv"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("s.flv"));
        int len;
        byte[] b = new byte[1024*8];
        while ((len = bis.read(b)) != -1){
            bos.write(b);
            bos.flush();
        }
        bos.close();
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
 
 
 

9.4 字符流

       當使用字節流讀取文本文件時,可能會遇到一個小問題。 就是遇到中文字符的時候,可能不會顯示完整的字符,那是因為一個中午字符 可能 占用多個字節。所有java提供了一些字符流,以字符為單位讀寫數據,專門用於處理文本文件。

        9.4.1 字符輸入流【Reader】

                java.io.Reader 抽象類是表搜狐用於讀取字符流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸入流的基本共性功能方法。
                       
  •  

    public void close() :關閉此流並釋放與此流相關聯的任何系統資源。
    public int read(): 從輸入流讀取一個字符。
    public int read(char[] cbuf): 從輸入流中讀取一些字符,並將它們存儲到字符數組 cbuf中 。

     

         9.4.2 FileReader 類

                    java.io.FileReader 類是讀取字符文件的類,構造時使用系統默認的字符編碼和默認字節緩沖區。
                       tips:
                                    1.字符編碼:字節與字符的對應規則。Windows 系統的中午編碼默認是GBK 編碼表
                                    2.字節緩沖區:一個字節數組,用來臨時存儲字節數據。
                            構造方法:
                                
FileReader(File file): 創建一個新的 FileReader ,給定要讀取的File對象。
FileReader(String fileName): 創建一個新的 FileReader ,給定要讀取的文件的名稱。
                                                當你創建一個流對象時,必須傳入一個文件路徑,類似於FileInputStream
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("a.txt");
        // 創建字符輸入流對象
        FileReader fr = new FileReader(file);
        
        // 使用文件名創建流對象
        FileReader fr1 = new FileReader("a.txt");
    }
 
 
                       基本方法:
                                 1.read方法,每次可以讀取一個字符的數據,提升為int類型,讀取到文件末尾,返回 -1 ,循環讀取
                                問:為什么 返回值是 int 而不是 byte
 答:因為字節輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是二進制形式存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111   那么這111111111是byte類型的-1我們程序要是遇到 -1 就會停止不讀了,后面的數據就讀取不到了 所以選擇 int接受,如果111111111會在前面補上24個0湊足4個字節,那么byte類型的-1 就變成int類型的255了 這樣就可以保證整個數據讀完了,而結束標記的-1就是int類型。
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
       // a.txt 文件中 有 abc
        File file = new File("a.txt");
        // 創建字符輸入流對象
        FileReader fr = new FileReader(file);
         // 定義遍歷保存數據
        int b;
        while ((b = fr.read()) != -1) {
            System.out.println("b = " + (char)b);
        }
        fr.close();
    }
結果輸出:
    a
    b
    c
    
            /** tips:
                 1.雖然讀取了一個字符,但是也會自動提升為int 類型 記得關閉流
                 */
 
 
             2.使用字符數組讀取: read(char[]  cbuf),每次讀取b個長度字符到數組中,返回讀取到的有效字符個數,讀取到末尾時,返回 -1 
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("read.txt");
        // 定義遍歷 保存有效字符個數
        int len;
        // 定義字符數組 作為裝字符數據的容器
        char[] buff = new char[2];
        // 進行循環讀取
        while ((len=fr.read(buff)) != -1){
            System.out.println("buff = " + new String(buff));
        }
        fr.close();
    }
結果:
buff = 我是
buff = 愛J
buff = av
buff = a語
buff = 言語
這樣會出現 緩沖區 內容 粘包一樣的問題
 
 
               優化;
<wiz_code_mirror>
 
 
 
 
 
   public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("read.txt");
        // 定義遍歷 保存有效字符個數
        int len;
        // 定義字符數組 作為裝字符數據的容器
        char[] buff = new char[2];
        // 進行循環讀取
        while ((len=fr.read(buff)) != -1){
            System.out.println("buff = " + new String(buff,0,len));
        }
        fr.close();
    }
結果:
buff = 我是
buff = 愛J
buff = av
buff = a語
buff = 
 
 

                9.4.3 字符輸出流【Writer】

                        java.io.Writer 抽象類 是表示用於寫出字符流的所有類的超類,將指定的字符信息寫到 目的地。它定義了字節輸出流的基本共性功能方法。
                        
  •  

    public abstract void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
    public abstract void flush() :刷新此輸出流並強制任何緩沖的輸出字符被寫出。
    public void write(int b) :寫出一個字符。
    `public void write(char[] cbuf)`:將 b.length字符從指定的字符數組寫出此輸出流。
    public abstract void write(char[] b, int off, int len) :從指定的字符數組寫出 len字符,從偏移量 off開始輸出到此輸出流。
    public void write(String str) :寫出一個字符串。
    1. FielWriter類                  
                                        java.io.FileWriter 類是寫出字符到文件的類 ,構造時 使用系統默認的字符編碼和默認字節緩沖區。
                                        構造方法:
                                            - FileWriter(File file): 創建一個新的 FileWriter,給定要讀取的File對象。   
- FileWriter(String fileName): 創建一個新的 FileWriter,給定要讀取的文件的名稱。
                                                當你創建一個流對象時,必須傳入一個文件路徑,類似於FileOutputStream
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        // 通過文件對象創建 字符輸出流對象
        FileWriter fw = new FileWriter(file);
        // 通過文件名字創建一個 字符輸出流對象
        FileWriter fw2 = new FileWriter("b.txt");
    }
 
 
                                            基本寫出數據方法:write()
                                     write(char[] buff)
                                                write(char[] buff, int off, int len)            與 FileOutputStream
                                               寫出字符串
                                     write(String str)和 write(String str , int of ,int len)
                                     flush :刷新緩沖區 ,流對象可以繼續使用
                                     close:關閉流 ,釋放系統資源,關閉前會刷新緩沖區
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        // 通過文件對象創建 字符輸出流對象
        FileWriter fw = new FileWriter(file);
        fw.write(97);
        fw.write('b');
        fw.write('c');
        fw.write(50000); // 中午編碼表中50000對應的一個漢字
        fw.close();
    }
結果:
    abc鱔
    
    notes:
            1.雖然參數int 類型是四個字節,但是只會保留一個字符 的信息寫出。
            2.沒有調用close方法,數據只是保存到了緩沖區,並未寫出到文件中
            3.即便是調用了 flush 方法 寫出了數據,操作的最后還是要 關閉流
 
 
                                                    續寫和換行 與FileOutputStream 類似

                        9.4.4 字符緩沖 輸入 輸出流

<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) throws IOException {
        // 創建字符 緩沖 輸入 輸出流
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
        // 首先 按照字節進行讀取
        int len ;
        char[] b = new char[1024];
        while ((len =  br.read(b)) != -1){
            bw.write(b,0,len);
            bw.flush();
        }
        bw.close();
        br.close();
    }
 
 
 
notes:
            字符流,只能操作文本文件,不能操作圖片,視頻等非文本文件。
    

9.4 IO異常的處理

        9.4.1 JDK 7 之前處理的方式

                        我們一直把異常拋出,而實際開發中並不能這樣處理,建議使用try...catch...finally 代碼塊,處理異常部分
                        
 
<wiz_code_mirror>
 
 
 
 
 
    public static void main(String[] args) {
       // 聲明變量
        FileWriter fw = null;
        try {
            //創建流對象
            fw = new FileWriter("fw.txt");
            // 寫出數據
            fw.write("我愛JAVA"); //我愛JAVA
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
 

                9.4.2 JDK 7 的處理方式

                                還可以使用JDK7優化后的try-with-resource 語句,該語句確保了每個資源在語句結束時關閉。所謂的資源(resource)是指在程序完成后,必須關閉的對象。
                            
 
<wiz_code_mirror>
 
 
 
 
 
格式:
    try (創建流對象語句,如果多個,使用';'隔開) {
 // 讀寫數據
} catch (IOException e) {
 e.printStackTrace();
}
演示:
    public static void main(String[] args) {
       // 創建流對象
        try ( FileWriter fw = new FileWriter("fw.txt"); ) {
            // 寫出數據
            fw.write("我愛java"); //我愛java
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
 
 

                        9.4.3 JDK9 的改動

                                          JDK9中try-with-resource 的改進,對於引入對象的方式,支持的更加簡潔。被引入的對象,同樣可以自動關閉,無需手動close,我們來了解一下格式。  
<wiz_code_mirror>
 
 
 
 
 
改進前的格式:
    // 被final修飾的對象
final Resource resource1 = new Resource("resource1");
// 普通對象
Resource resource2 = new Resource("resource2");
// 引入方式:創建新的變量保存
try (Resource r1 = resource1;
     Resource r2 = resource2) {
     // 使用對象
}
改進后的格式:
    // 被final修飾的對象
final Resource resource1 = new Resource("resource1");
// 普通對象
Resource resource2 = new Resource("resource2");
// 引入方式:直接引入
try (resource1; resource2) {
     // 使用對象
}
演示;'
       public static void main(String[] args) throws IOException {
        // 創建流對象
        final  FileReader fr  = new FileReader("in.txt");
        FileWriter fw = new FileWriter("out.txt");
        // 引入到try中
        try (fr; fw) {
           // 定義變量
            int b;
           // 讀取數據
           while ((b = fr.read())!=-1) {
             // 寫出數據
             fw.write(b);
           }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }     
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM