1. 程式人生 > 實用技巧 >節點流(檔案流)

節點流(檔案流)

節點流

FileReader和FileWriter

字元流(cha[]陣列)

FileReader讀入資料的基本操作

過程

  1. 例項化File類的物件,指明要操作的檔案

    注意:

    • 在@Test測試中的相對路徑是相對於當前Module

    • 在main函式的相對路徑是相對於當前工程

  2. 提供具體的流

  3. 資料的讀入過程

  4. 流的關閉操作

  5. try-catch-finally異常處理

說明

  • 一定要注意最後流的關閉
  • read()的理解:返回讀入的一個字元。如果達到檔案末尾,返回-1
  • 異常的處理:為了保證流資源一定可以執行關閉的操作,需要使用try-catch-finally來處理
  • 讀入的檔案(hello.txt)一定要存在,否則會報FileNotFoundException異常

程式碼實現

@org.junit.Test
public void test1(){
    FileReader fileReader = null;
    try {
        //1. 例項化File類的物件,指明要操作的檔案
        //注意:在@Test測試中的相對路徑是相對於當前Module,在main函式的相對路徑是相對於當前工程
        File file = new File("hello.txt");//相對路徑

        //2. 提供具體的流
        fileReader = new FileReader(file);

        //3. 資料的讀入過程
        //read():返回讀入的一個字元。如果達到檔案末尾,返回-1
        //方式一
//      int data = fileReader.read();
//      while(data != -1){
//          System.out.print((char)data);
//          data = fileReader.read();
//      }

        //方式二:語法上針對方式一的修改
        int data;
        while((data = fileReader.read()) != -1){
            System.out.println((char)data);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        //4. 流的關閉操作
        try {
            //防止最開始提供流是出現異常導致這裡是空指標,所以加一個判斷
            if(fileReader != null){
                fileReader.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

執行結果

此時的"hello.txt"文件中儲存的內容是hello

使用read()的過載方法

  • read():返回讀入的一個字元。如果達到檔案末尾,返回-1
  • read(char[] cbuf):返回每次讀入cbuf陣列中的字元的個數。如果達到檔案末尾,返回-1(常用)
  • read(char cbuf[], int off, int len) (不常用)
read(char[] cbuf)的用法
  1. 建立一個char的陣列cbuf

    (舉例假定該陣列的長度為5)

    char[] cbuf = new char[5];

  2. 建立len變數,儲存read(char[] cbuf)的返回值

    (注意:返回值即為每次讀入cbuf陣列中的字元的個數)

  3. 讀取資料

    • 寫法一:迴圈遍歷
    for (int i = 0; i < len; i++) {
        System.out.print(cbuf[i]);
    }
    
    • 寫法二:char[]型別和String型別轉換
    String str = new String(cbuf,0,len);
    System.out.print(str);
    

    https://www.cnblogs.com/CrabDumplings/p/13341279.html

  4. 流的關閉操作(不要忘記)

read(char[] cbuf)讀取資料時的注意事項
  • 寫法一

    for (int i = 0; i < len; i++) {
        System.out.print(cbuf[i]);
    }
    

    其中for迴圈時,i一定要小於len(每次讀入cbuf陣列中的字元的個數)而不是cbuf.length

    • 畫圖說明:

      最後還剩下3個數據的時候:

      • 如果for迴圈中的i小於cbuf.length(錯誤的寫法)

        最後的輸出為:helloWorld123ld

        (其中hello為第一次的結果,World為第二次的結果,123ld為第三次的結果)

        而檔案中的內容為helloWorld123,所以此時的寫法是錯誤的

      • 如果for迴圈中的i小於len(正確的寫法)

        最後的輸出為:helloWorld123

        (其中hello為第一次的結果,World為第二次的結果,123為第三次的結果)

  • 寫法二

    String str = new String(cbuf,0,len);
    System.out.print(str);
    

    其中利用了String(char[] value, int offset, int count)構造器,而不是String(char[] value)構造器

    • String(char[] value)構造器(錯誤的寫法)
      錯誤原因與寫法一錯誤的方法相同

    • String(char[] value, int offset, int count)構造器(正確的寫法)

      讀取char[]陣列中角標0到角標len的內容,過程與寫法一正確的方法過程類似

FileReader寫出資料的基本操作

過程

  1. 例項化File類的物件,指明要操作的檔案
  2. 提供具體的流
  3. 資料的寫出過程
  4. 流的關閉操作
  5. try-catch-finally異常處理

說明

寫出操作,對應的File可以不存在。

  • 如果不存在,在寫出的過程中,會自動建立此檔案
  • 如果存在這個檔案
    • 對原有檔案的覆蓋

      流使用的構造器為

      FileWriter(file, false)

      或者是

      FileWriter(file)

    • 在原有檔案的基礎上追加內容(不會對原有檔案進行覆蓋)

      流使用的構造器為

      FileWriter(file, true)

程式碼實現

FileWriter fw1 = null;
FileWriter fw2 = null;
try {
    //1. 提供File類的物件,指明寫出到的檔案
    File file = new File("hi.txt");

    //2. 提供FileWriter的物件,用於檔案的寫出
    //覆蓋
    fw1 = new FileWriter(file,false);
    //不覆蓋
    fw2 = new FileWriter(file,true);
    //3. 寫出的操作
    fw1.write("I have a dream!\n");
    fw2.write("123\n");
} catch (IOException e) {
    e.printStackTrace();
}finally {
    //4. 關閉流資源
    if(fw1 != null)
        try {
            fw1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fw2 != null)
                try {
                    fw2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        } 
}

執行結果

最開始hi.txt檔案中的內容為hello
執行程式碼後

使用FileWriter和FileReader實現文字檔案的複製

過程

  1. 建立File類的物件,指明讀入和寫出的檔案
  2. 建立輸入流和輸出流的物件
  3. 資料的讀入和寫入操作
  4. 關閉流資源
  5. try-catch-finally異常處理

說明

  • 在讀取檔案檔案時,選擇read(char[] cbuf)的用法

  • 在寫入檔案的時候,注意不要寫成

    fw.write(cbuf);

    此時出現的錯誤和讀取操作時寫法一會出現的錯誤相同,不可以正確的讀取檔案中原本的內容

    需要使用

    fw.write(cbuf,0,len);

    讀取cbuf陣列中角標為0的元素到角標為len的元素

  • 在最後關閉流資源的時候,一定要注意兩個流都要關閉,即使其中一個流在關閉的時候丟擲異常另一個流也要關閉

    有兩種寫法

    • 寫法一
    finally {
        //4. 關閉流資源
        if(fr != null)
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(fw != null)
                    try {
                        fw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            }
    }
    
    • 寫法二
    finally {
        //4. 關閉流資源
        try {
            if(fr != null)
                fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        try {
            if(fw != null)
                fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

程式碼實現

public void test4(){
    FileReader fr = null;
    FileWriter fw = null;
    try {
        //1. 建立File類的物件,指明讀入和寫出的檔案
        File file1 = new File("hello.txt");
        File file2 = new File("hi.txt");
        //2. 建立輸入流和輸出流的物件
        fr = new FileReader(file1);
        fw = new FileWriter(file2,true);
        //3. 資料的讀入和寫入操作
        char[] cbuf = new char[5];
        int len;//記錄每次讀入到cbuf陣列中字元的個數
        while((len = fr.read(cbuf)) != -1){
            //每次寫出len個字元
            fw.write(cbuf,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        //4. 關閉流資源
        try {
            if(fr != null)
                fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            if(fw != null)
                fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

執行結果

注意

字元流不能處理圖片檔案等位元組資料!!!

FileInputStream和FileOutputStream

位元組流(byte[])

使用FileInputStream和FileOutputStream實現文字檔案的複製

過程

  1. 建立File類的物件,指明讀入和寫出的檔案
  2. 建立輸入流和輸出流的物件
  3. 資料的讀入和寫入操作
  4. 關閉流資源
  5. try-catch-finally異常處理

程式碼實現

FileInputStream fis = null;
FileOutputStream fos = null;
try {
    File srcfile = new File("殷志源.png");
    File destfile = new File("丸子.png");

    fis = new FileInputStream(srcfile);
    fos = new FileOutputStream(destfile);

    byte[] buffer = new byte[5];
    int len;
    while((len = fis.read(buffer)) != -1){
        fos.write(buffer,0,len);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if(fis != null)
            fis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    try {
        if(fos != null)
            fos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

執行結果


指定路徑下檔案的複製的方法

複製視訊

public void copyFile(String srcPath, String destPath){
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        File srcfile = new File(srcPath);
        File destfile = new File(destPath);

        fis = new FileInputStream(srcfile);
        fos = new FileOutputStream(destfile);

        byte[] buffer = new byte[1024];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if(fis != null)
                fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            if(fos != null)
                fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

位元組流和字元流使用的注意事項

  • 對於文字檔案(.txt, .java, .c, .cpp......),使用字元流來處理
  • 對於非文字檔案(.jpg, .mp3, .mp4, .avi, .doc, .ppt......),使用位元組流來處理
  • 如果只是想複製文字檔案,也可以使用位元組流(流在此時只是個搬運的作用)
  • 非文字只可以用位元組流操作