JAVA詳細解析之IO流、File、位元組流以及字元流

2022-04-14 16:00:13
本篇文章給大家帶來了關於的相關知識,其中主要介紹了關於IO流、File、位元組流、字元流的相關問題,下面就一起來看一下,希望對大家有幫助。

推薦學習:《》

IO簡介

1 Stream

在學習IO流之前,我們首先需要學習的概念就是Stream流
為了方便理解,我們可以把資料的讀寫操作抽象成資料在"管道"中流動,但需注意:
1.流只能單方向流動
2.輸入流用來讀取 → in
3.輸出流用來寫出 → out
4.資料只能從頭到尾順序的讀寫一次
所以以程式的角度來思考,In/out 相對於程式而言的輸入(讀取)/輸出(寫出)的過程.
在這裡插入圖片描述

2 IO流的繼承結構

在java中,根據處理的資料單位不同,可以把流分為位元組流和字元流
位元組流 : 針對二進位制檔案
字元流 : 針對文字檔案
再結合對應型別的輸入和輸出方向,常用的流有:

File

位元組流:針對二進位制檔案

InputStream

FileInputStream
BufferedInputStream
ObjectInputStream

OutputStream

FileOutputStream
BufferedOutputStream
ObjectOutputStream

字元流:針對文字檔案

Reader

FileReader
BufferedReader
InputStreamReader

Writer

FileWriter
BufferedWriter
OutputStreamWriter
PrintWriter一行行寫出

3 File檔案類

3.1概述

封裝一個磁碟路徑字串,對這個路徑可以執行一次操作
可以封裝檔案路徑、資料夾路徑、不存在的路徑

3.2建立物件

File(String pathname)通過將給定路徑名字串轉換為抽象路徑名來建立一個新的File範例
new File(「d:/abc/a.txt」);
new File(「d:/abc」,」a.txt」);

3.3常用方法

在這裡插入圖片描述

3.4 練習:測試常用方法

建立包: cn.tedu.file
建立類: TestFile.java

package cn.tedu.file;import java.io.File;import java.io.IOException;import java.util.Arrays;/*本類用於測試檔案類File*/public class TestFile {
    public static void main(String[] args) throws IOException {
        //1.建立File類物件
        /*1.ready目錄與1.txt需要自己手動建立
        * 2.File需要導包:import java.io.File;
        * 3.路徑是String型別,必須寫正確,不然找不到檔案
        * 4.完整的檔名包含兩部分:檔名+字尾名*/
        File file = new File("E:\\ready\\1.txt");

        //2.1測試File中的常用方法
        System.out.println(file.length());//3,獲取檔案的位元組量
        System.out.println(file.exists());//true,判斷檔案是否存在
        System.out.println(file.isFile());//true,判斷是否為檔案
        System.out.println(file.isDirectory());//false,判斷是否為資料夾
        System.out.println(file.getName());//1.txt獲取檔名
        System.out.println(file.getParent());//E:\ready 獲取父級路徑
        System.out.println(file.getAbsolutePath());//E:\ready\1.txt 獲取帶碟符的完整路徑:絕對路徑

        //2.2 測試建立與刪除
        /*new 只會幫你在記憶體中建立一個File型別的物件
        * 並不會幫你在磁碟中建立一個真實存在的2.txt檔案*/
        file = new File("E:\\ready\\2.txt");

        //建立一個之前不存在的檔案2.txt,如果建立成功,會返回true
        /*如果指定建立檔案的路徑不對,會丟擲異常:java.io.Exception
        * 所以需要提前處理這個問題,我們暫時選擇在main()上丟擲
        * 這個IO異常是目前我們遇到的強制要求必須預先處理的異常
        * 如果不處理,方法的呼叫會報錯,通不過編譯*/
        System.out.println(file.createNewFile());//建立之前不存在的檔案

        file = new File("E:\\ready\\m");
        System.out.println(file.mkdir());//建立之前不存在的單層資料夾

        file = new File("E:\\ready\\a\\b\\c");
        System.out.println(file.mkdirs());//建立之前不存在的多層資料夾

        System.out.println(file.delete());//c被刪除,刪除空資料夾或者檔案

        file = new File("E:\\ready\\a");
        System.out.println(file.delete());//false,a資料夾不是空的,裡面有內容

        file = new File("E:\\ready\\2.txt");
        System.out.println(file.delete());//2.txt被刪除,可以刪除檔案

        //2.3測試展示檔案列表
        file = new File("E:\\ready");
        String[] list = file.list();/*不常用*/
        System.out.println(Arrays.toString(list));
        //這句話會報錯,因為這是一個String[],所以陣列中每個元素都是String型別的
        //那麼只能用String類中的方法,而isDirectory()是File類中的方法
        //System.out.println(list[0].isDirectory());

        File[] fs = file.listFiles();/*常用*/
        System.out.println(Arrays.toString(fs));
        System.out.println(fs[0].isDirectory());
    }}

4 位元組流讀取

位元組流是由位元組組成的,字元流是由字元組成的.
Java裡字元由兩個位元組組成.位元組流是基本流,主要用在處理二進位制資料。
所以位元組流是比較常用的,可以可以處理多種不同種類的檔案,比如文字檔案/音訊/視訊等等

4.1 InputStream抽象類

此抽象類是表示位元組輸入流的所有類的超類/抽象類,不可建立物件哦

常用方法:
abstract int read() 從輸入流中讀取資料的下一個位元組
int read(byte[] b) 從輸入流中讀取一定數量的位元組,並將其儲存在緩衝區陣列 b 中
int read(byte[] b, int off, int len) 將輸入流中最多 len 個資料位元組讀入 byte 陣列,off表示存時的偏移量
void close() 關閉此輸入流並釋放與該流關聯的所有系統資源

4.2 FileInputStream子類

直接插在檔案上,直接讀取檔案資料

建立物件
FileInputStream(File file)—直接傳檔案物件
通過開啟一個到實際檔案的連線來建立一個 FileInputStream,該檔案通過檔案系統中的 File 物件 file 指定FileInputStream(String pathname)—傳路徑
通過開啟一個到實際檔案的連線來建立一個 FileInputStream,該檔案通過檔案系統中的路徑名 name 指定

4.3 BufferedInputStream子類

BufferedInputStream 為另一個輸入流新增一些功能,在建立BufferedInputStream 時,會建立一個內部緩衝區陣列(預設8k大小)。在讀取或跳過流中的位元組時,可根據需要從包含的輸入流再次填充該內部緩衝區,一次填充多個位元組。

建立物件
BufferedInputStream(InputStream in)
建立一個 BufferedInputStream 並儲存其引數,即輸入流 in,以便將來使用。

4.4 練習:位元組流讀取案例

建立包: cn.tedu.file
建立類: TestIn.java

package cn.tedu.file;import java.io.*;/*本類用於練習位元組輸入流*/public class TestIn {
    public static void main(String[] args) {
        //method();//位元組流的讀取
        method2();//高效位元組流的讀取
    }

    //本方法用於測試高效位元組流的讀取
    private static void method2() {
        //定義一個在本方法中都生效的區域性變數in,注意手動初始化,值為null
        InputStream in = null;
        try {
            //1.建立高效位元組輸入流物件//            InputStream in = new BufferedInputStream(//                    new FileInputStream(new File("E:\\ready\\1.txt")));
              in = new BufferedInputStream
                      (new FileInputStream("E:\\ready\\1.txt"));
            //2.使用流進行讀取
            int b;
            while ((b= in.read())!= -1){
                System.out.println(b);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {//關流操作寫在finally{}中
            //3.流用完以後一定要關閉!!!
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    //本方法用於測試位元組流的讀取
    private static void method() {
        //建立一個在本方法都生效的區域性變數注意手動初始化
        InputStream in = null;
        try {
            //1.建立位元組輸入流物件用於讀取
            //InputStream in = new InputStream();//報錯原因:抽象類不可範例化
            //InputStream in = new FileInputStream(new File("E:\\ready\\1.txt"));
            in = new FileInputStream("E:\\ready\\1.txt");
            //2.開始讀取
            /*read()每次呼叫都會讀取一個位元組,如果讀到了資料的末尾,返回-1*///            System.out.println(in.read());//            System.out.println(in.read());//            System.out.println(in.read());//            System.out.println(in.read());
            //需求:需要回圈讀取檔案中的所有內容,直至讀完
            //定義變數,記錄讀到的資料
            int b;
            while((b=in.read())!= -1){
                System.out.println(b);
            }
        } catch (Exception e) {
            e.printStackTrace();//列印錯誤資訊
        /*try-catch結構中的第三個部分:finally{}
        * 這部分不論是否捕獲到異常,是一定會被執行到的程式碼,常用於關流*/
        }finally {
            try {
                //3.釋放資源,流資源用完必須釋放!!!
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }}

5 字元流讀取

常用於處理純文字資料,讀寫容易出現亂碼的現象,在讀寫時,最好指定編碼集為UTF-8

5.1 Reader抽象類

用於讀取字元流的抽象類。

常用方法:
int read() 讀取單個字元
int read(char[] cbuf) 將字元讀入陣列
abstract int read(char[] cbuf, int off, int len) 將字元讀入陣列的某一部分
int read(CharBuffer target) 試圖將字元讀入指定的字元緩衝區
abstract void close() 關閉該流並釋放與之關聯的所有資源

5.2 FileReader子類

用來讀取字元檔案的便捷類。此類的構造方法假定預設字元編碼和預設位元組緩衝區大小都是適當的。要自己指定這些值,可以先在 FileInputStream 上構造一個 InputStreamReader。

建立物件
FileReader(String fileName) 在給定從中讀取資料的檔名的情況下建立一個新 FileReader
FileReader(File file) 在給定從中讀取資料的 File 的情況下建立一個新 FileReader

5.3 BufferedReader子類

從字元輸入流中讀取文字,緩衝各個字元,從而實現字元、陣列和行的高效讀取。
可以指定緩衝區的大小,或者可使用預設的大小。大多數情況下,預設值就足夠大了。

建立物件
BufferedReader(Reader in) 建立一個使用預設大小輸入緩衝區的緩衝字元輸入流

5.4 練習:字元流讀取案例

建立包: cn.tedu.file
建立類: TestIn2.java

package cn.tedu.file;import java.io.*;/*本類用於測試字元流的讀取*/public class TestIn2 {
    public static void main(String[] args) {
        //method();//測試普通字元輸入流
        method2();//測試高效字元輸入流
    }
    //建立一個用於測試高效字元輸入流的方法
    private static void method2() {
        //1.定義一個在本方法都生效的區域性變數,手動初始化值null
        Reader in=null;
        try{
            //1.建立高效字元讀取流物件
            //in = new BufferedReader(new FileReader(new File("E:\\ready\\1.txt")));
            in = new BufferedReader(new FileReader("E:\\ready\\1.txt"));
            //2.使用流物件
            int b;
            while((b=in.read())!=-1){
                System.out.println(b);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //3.關閉流物件
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //建立一個用於測試普通字元輸入流的方法
    private static void method() {
        //1.1建立一個在本方法中都生效的區域性變數,注意初始化值null
        Reader in = null;
        try {
            //1.2建立字元輸入流物件,注意需要捕獲異常
            //Reader in = new Reader();//報錯原因:抽象父級不可範例化
            //in = new FileReader(new File("E:\\ready\\1.txt"));
            in = new FileReader("E:\\ready\\1.txt");
            //2.使用流物件
            //System.out.println(in.read());
            //需求:迴圈讀取檔案中的所有內容,只要不是-1,就說明還有資料,繼續讀取
            //3.1定義變數,記錄讀取到的資料
            int b;
            while((b = in.read())!= -1){
                System.out.println(b);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//3.關流
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }}

6 位元組流寫出

6.1 OutputStream抽象類

此抽象類是表示輸出位元組流的所有類的超類.輸出流接受輸出位元組並將這些位元組傳送到某個接收器.

常用方法:
Void close() 關閉此輸出流並釋放與此流相關的所有系統資源
Void flush() 重新整理此輸出流並強制寫出所有緩衝的輸出位元組
Void write(byte[ ] b) 將b.length個位元組從指定的byte陣列寫入此輸出流
Void write(byte[ ] b,int off ,int len) 將指定byte陣列中從偏移量off開始的len個位元組寫入輸出流
Abstract void write(int b) 將指定的位元組寫入此輸出流

6.2 FileOutputStream 子類

直接插在檔案上,直接寫出檔案資料

構造方法(建立物件):
FileOutputStream(String name)
建立一個向具有指定名稱的檔案中寫入資料的檔案輸出流
FileOutStream(File file)
建立一個向指定File物件表示的檔案中寫入資料的檔案輸出流
FileOutStream(File file,boolean append)—如果第二個引數為true,表示追加,不覆蓋
建立一個向指定File物件表示的檔案中寫入資料的檔案輸出流,後面的引數是指是否覆蓋原檔案內容

6.3 BufferedOutputstream 子類

該類實現緩衝的輸出流,通過設定這種輸出流,應用程式就可以將各個位元組寫入底層輸出流中,而不必每次針對位元組寫出呼叫底層系統

構造方法(建立物件):
BufferedOutputStream(OutputStream out)
建立一個新的緩衝輸出流,用以將資料寫入指定的底層輸出流

6.4 練習: 位元組輸出流測試:

建立包: cn.tedu.file
建立類: TestOut.java

package cn.tedu.file;import java.io.*;/*本類用於測試位元組輸出流*/public class TestOut {
    public static void main(String[] args) {
        method();//用於測試普通位元組輸出流
        //method2();//用於測試高效位元組輸出流
    }
    //建立一個用於測試高效位元組輸出流的方法
    private static void method2() {
        //1.建立一個在本方法都生效的區域性變數,注意手動初始化
        OutputStream out = null;
        try{
            //2.建立高效位元組輸出流物件//          out = new BufferedOutputStream(new FileOutputStream(new File("E:\\ready\\2.txt")));
            out = new BufferedOutputStream(new FileOutputStream("E:\\ready\\2.txt"));
            //3.使用流物件--進行寫出操作
            out.write(97);
            out.write(97);
            out.write(97);
        }catch (Exception e){
            e.printStackTrace();
        }finally {//關流操作要放在finally{}中
            try {
                //4.關流
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //建立一個用於測試普通位元組輸出流的方法
    private static void method() {
        //1.建立一個在本方法中都生效的區域性變數,注意手動初始化null
        OutputStream out = null;
        //2.建立try-catch-finally結構,因為IO操作可能會產生異常
        try{
            //3.建立普通位元組輸出流物件
            //out = new FileOutputStream(new File("E:\\ready\\2.txt"));
            //out = new FileOutputStream("E:\\ready\\2.txt");
            out = new FileOutputStream("E:\\ready\\2.txt",true);
            //4.使用流物件--進行寫出操作
            out.write(99);//對應ASCII碼錶中的a
            out.write(99);//對應ASCII碼錶中的b
            out.write(99);//對應ASCII碼錶中的c
        }catch (Exception e){
            e.printStackTrace();
        }finally {//如果想要程式碼一定會執行,需要寫在finally中
            try {
                //5.關流操作
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }}

7 字元流寫出

7.1 Writer 抽象類

寫入字元流的抽象類

常用方法:
Abstract void close() 關閉此流,但要先重新整理它
Void write(char[ ] cbuf) 寫入字元陣列
Void write(int c) 寫入單個字元
Void write(String str) 寫入字串
Void write(String str,int off,int len) 寫入字串的某一部分
Abstract void write(char[] cbuf,int off,int len)寫入字元陣列的某一部分

7.2 FileWriter 子類

用來寫入字元檔案的便捷類,此類的構造方法假定預設字元編碼和預設位元組緩衝區大小都是可接受的.如果需要自己自定義這些值,可以先在FileOutputStream上構造一個OutputStreamWriter.

構造方法(建立物件):
FileWriter(String filename)
根據給定的檔名構造一個FileWriter物件
FileWriter(String filename,boolean append)
根據給定的檔名以及指示是否附加寫入資料的boolean值來構造FileWriter

7.3 BufferedWriter子類

將文字寫入字元輸出流,緩衝各個字元,從而提供單個字元,陣列和字串的高效寫入.可以指定緩衝區的大小,或者接受預設的大小,在大多數情況下,預設值就足夠大了

構造方法(建立物件):
BufferedWriter(Writer out)
建立一個使用預設大小輸出緩衝區的緩衝字元輸出流

7.4 練習: 字元輸出流測試:

建立包: cn.tedu.file
建立類: TestOut2.java

package cn.tedu.file;import java.io.*;/*本類用於測試字元輸出流*/public class TestOut2 {
    public static void main(String[] args) {
        //method();//用於測試普通字元輸出流
        method2();//用於測試高效字元輸出流
    }
    //建立一個用於測試高效字元輸出流的方法
    private static void method2() {
        //1.建立一個在本方法都生效的區域性變數,值為null,注意手動初始化!!!
        Writer out = null;
        //2.由於程式可能會丟擲異常,所以需要寫一個try-catch-finally結構
        try{//存放可能會丟擲異常的程式碼
            //3.建立普通字元輸出流物件
            //out = new BufferedWriter(new FileWriter(new File("E:\\ready\\2.txt")));
            //out = new BufferedWriter(new FileWriter("E:\\ready\\2.txt"));
            out = new BufferedWriter(new FileWriter("E:\\ready\\2.txt",true));
            //4.使用流物件
            out.write(100);
            out.write(100);
            out.write(100);
            out.write(100);
            out.write(100);
        }catch (Exception e){//匹配並捕獲異常
            e.printStackTrace();//如果捕獲到異常就列印錯誤資訊
        }finally {//一定會被執行到的程式碼塊,常用於關流
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //建立一個用於測試普通字元輸出流的方法
    private static void method() {
        //1.建立一個在本方法都生效的區域性變數,值為null,注意手動初始化!!!
        Writer out = null;
        //2.由於程式可能會丟擲異常,所以需要寫一個try-catch-finally結構
        try{//存放可能會丟擲異常的程式碼
            //3.建立普通字元輸出流物件
            //out = new FileWriter(new File("E:\\ready\\2.txt"));
            //out = new FileWriter("E:\\ready\\2.txt");
            out = new FileWriter("E:\\ready\\2.txt",true);
            //4.使用流物件
            out.write(98);
            out.write(98);
            out.write(98);
            out.write(98);
        }catch (Exception e){//匹配並捕獲異常
            e.printStackTrace();//如果捕獲到異常就列印錯誤資訊
        }finally {//一定會被執行到的程式碼塊,常用於關流
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }}

8 拓展

通過學習以上的幾種流,我們也可以拓展嘗試做下檔案的複製:
建立包: cn.tedu.file
建立類: TestCopyFile.java

package cn.tedu.file;import java.io.*;import java.util.Scanner;/*本類用於練習檔案複製綜合案例*/public class TestCopyFile {
    public static void main(String[] args) {
        //1.提示並接收使用者輸入的兩個路徑
        System.out.println("請輸入原始檔路徑");//--被複制的那個檔案
        String f = new Scanner(System.in).nextLine();
        System.out.println("請輸入新檔案路徑:");//--複製好的新檔案
        String t = new Scanner(System.in).nextLine();

        //2.呼叫建立好的自定義方法完成檔案複製
        //ZFCopy(f,t);//用字元流完成檔案的複製案例
        ZJCopy(f,t);//用位元組流完成檔案的複製案例
    }
    //利用位元組流完成檔案複製案例
    private static void ZJCopy(String f, String t) {
        //1.定義在整個方法都生效的區域性變數,注意手動初始化,參照型別預設值為null
        InputStream in = null;
        OutputStream out = null;
        //2.由於程式碼可能會發生異常,所以需要編寫try-catch-finally結構
        try{
            //3.1建立高效位元組輸入流物件--FIS的引數是使用者傳入的原始檔路徑f
            in = new BufferedInputStream(new FileInputStream(f));
            //3.2建立高效位元組輸出流物件--FOS的引數是使用者傳入的新檔案路徑t
            out = new BufferedOutputStream(new FileOutputStream(t));

            //4.利用建立好的流物件完成業務
            //4.1定義變數用來儲存讀到的資料
            int b;
            //4.2迴圈讀取原始檔中的資料,只要不是-1,說明還有資料迴圈繼續
            while((b = in.read()) != -1){
                //4.3將讀到的資料寫入到新檔案中
                out.write(b);
            }
            System.out.println("恭喜您!檔案複製成功!");
        }catch (Exception e){
            System.out.println("很抱歉!檔案複製失敗!");
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //利用字元流完成檔案複製案例
    private static void ZFCopy(String f, String t) {
        //1.定義在整個方法中都生效的區域性變數,注意手動初始化,預設值為null
        Reader in = null;
        Writer out = null;
        //2.由於程式碼可能會發生異常,所以需要編寫try-catch-finally結構
        try{
            //3.1建立高效字元輸入流物件
            in = new BufferedReader(new FileReader(f));
            //3.2建立高效字元輸出流物件
            out = new BufferedWriter(new FileWriter(t));

            //4.拿到流物件以後,就可以使用流物件來完成業務了
            //4.1定義變數用來儲存讀到的資料
            int b;
            //4.2迴圈讀取原始檔,直到返回值為-1,說明沒有資料了,再結束迴圈
            while ((b=in.read())!=-1) {
                //4.3將本輪迴圈中讀到的資料寫入到新檔案中
                out.write(b);
            }
            System.out.println("恭喜您!檔案複製成功!");
        }catch (Exception e){
            System.out.println("很抱歉!檔案複製失敗!");
            e.printStackTrace();
        }finally {
            /*關流是有順序的:如果有多個流,最後建立的流最先關閉
            * 多條關流語句需要各自try-catch*/
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }}

9 總結:IO的繼承結構

1.主流分類

  1. 按照方向進行分類:輸入流 輸出流(相對於程式而言,從程式寫資料到檔案中是輸出)
  2. 按照傳輸型別進行分類:位元組流 字元流
  3. 組合: 位元組輸入流 位元組輸出流 字元輸入流 字元輸出流

2.學習方法:在抽象父類別中學習通用的方法,在子類中學習如何建立物件
3.位元組輸入流:

InputStream 抽象類,不能new,可以作為超類,學習其所提供的共性方法
--FileInputStream 子類,操作檔案的位元組輸入流,普通類
--BufferedInputStream 子類,緩衝位元組輸入流,普通類

4.字元輸入流

Reader 抽象類,不能new,可以作為超類,學習其所提供的共性方法
--FileReader,子類,操作檔案的字元輸入流,普通類
--BufferedReader,子類,緩衝字元輸入流,普通類

5.位元組輸出流:

OutputStream 抽象類,不能new,可以作為超類,學習其所提供的共性方法
--FileOutputStream 子類,操作檔案的位元組輸出流,普通類
--BufferedOutputStream 子類,緩衝位元組輸出流,普通類

6.字元輸出流

Writer 抽象類,不能new,可以作為超類,學習其所提供的共性方法
--FileWriter,子類,操作檔案的字元輸出流,普通類
--BufferedWriter,子類,緩衝字元輸出流,普通類

推薦學習:《》

以上就是JAVA詳細解析之IO流、File、位元組流以及字元流的詳細內容,更多請關注TW511.COM其它相關文章!