博客 / 詳情

返回

Java IO 基礎知識全面總結

引言

Java IO(Input輸入/Output輸出)框架扮演着至關重要的角色,它是數據交換和文件處理的基石。
數據輸入到計算機內存的過程即輸入,反之輸出到外部存儲(比如數據庫,文件,遠程主機)的過程即輸出。數據傳輸過程類似於水流,因此稱為 IO 流。
image.png

一、Java IO體系概覽

Java IO 流有40多個類,他們都是從如下 4 個抽象類基類中派生出來的。

抽象基類 字節流 字符流
輸入流 InputStream Reader
輸出流 OutputStream Writer

字節流和字符流有什麼區別

  • 字節流:以字節(8位)為單位進行數據的讀寫。它是計算機中最基本的數據傳輸單元,適用於處理包括文本、圖像、音頻、視頻等在內的二進制數據。
  • 字符流:以字符為單位進行數據的讀寫。字符流在處理時,會根據指定的字符編碼(如UTF-8、GBK等)將字符轉換為字節進行處理。由於一個字符可能佔用多個字節(具體取決於編碼方式),主要用於處理文本數據。

IO 流的分類

類型 名稱 説明
按功能分 輸入流,輸出流 輸入流的類以InputStream, Reader為後綴。輸出流的類以OutputStream, Writer未後綴。
按照類型分 字節流、字符流 節點流的類以InputStream,OutputStream為後綴,字符流以Reader,Writer為後綴
按角色或功能層次 節點流(低級流、原始流)、包裝流(處理流、高級流) 節點流 它是直接從數據源或目的地讀寫數據的流。除了對原數據進行讀取的節點流外,其他都是包裝流

下圖展示IO流系統圖-常用的類
image.png

二、IO操作之文件與目錄的操作

介紹File類,包括如何創建、刪除文件或目錄,檢查文件屬性等。

package file;

import org.junit.Test;

import java.io.File;
import java.io.IOException;

public class studyOfFile {
    @Test
    public void createFile() throws IOException {
        String filePath = "/Users/wu/file";
        File file = new java.io.File(filePath);
        /*創建文件*/
        file.createNewFile();

        /*查看文件的一下屬性*/
        System.out.println("創建文件成功 ~");
        System.out.println("文件名字: " + file.getName());
        System.out.println("文件是否存在: " + file.exists());
        System.out.println("文件是否是文件: " + file.isFile());
        System.out.println("文件的路徑: " + file.getAbsolutePath());
        System.out.println("文件是否擁有讀權限 " + file.canRead());
        System.out.println("文件是否存在: " + file.exists());

        /*刪除文件*/
        file.delete();
        System.out.println("刪除文件成功 ~");
        System.out.println("文件是否存在: " + file.exists());
    }

    @Test
    public void createDirectory() {
        String directory = "/Users/wu/studyIo";
        File file = new java.io.File(directory);
        /*創建目錄*/
        file.mkdir();

        /*查看目錄的一下屬性*/
        System.out.println("創建目錄成功 ~");
        System.out.println("文件是否是文件: " + file.isFile());
        System.out.println("文件是否是目錄: " + file.isDirectory());

        /*刪除目錄*/
        file.delete();
        System.out.println("刪除目錄成功 ~");
        System.out.println("目錄是否存在: " + file.exists());
    }
}

文件操作執行結果:
image.png
目錄操作的執行結果:
image.png

三、以案例學習OI流

在本小節將展示一下內容:
字節流:FileInputStream和FileOutStream
字符流:FileReader和FileWiter
包裝流:BufferedInputStream

<-- FileReader和FileWiter的用法和下面的例子很類似,就不在寫demo了-->

FileInputStream例子

這個例子將演示如何使用FileInputStream來讀取文件內容,並使用FileOutputStream將讀取的內容寫入另一個文件。

package demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamExample {
    public static void main(String[] args) {
        String sourcePath = "/Users/wu/studyIo/source.txt";
        String targetPath = "/Users/wu/studyIo/target.txt";

        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            /*創建一個source.txt文件 用於從source.txt文件中讀取去數據*/
            fis = new FileInputStream(sourcePath);
            /*創建一個target.txt文件 用於將讀到的數據寫到target.txt文件中*/
            fos = new FileOutputStream(targetPath);


            /*設置緩衝區的大小 一次讀取1024字節*/
            byte[] buffer = new byte[1024];
            int length;

            /*read方法放回讀取的字節數,讀取完畢返回-1*/
            while ((length = fis.read(buffer)) > -1) {
                /*邊讀邊寫*/
                fos.write(buffer, 0, length);
            }

            System.out.println("文件複製完成。");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    /*記得關閉 釋放資源*/
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    /*真正執行寫的操作,否則寫入不成功*/
                    fos.write(0);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

這裏我遇到了一個問題:
fis = new FileInputStream(sourcePath);按理可以直接創建文件的。因為它的源代碼是這樣寫的
image.png
我會報錯
image.png
手動創建上兩個文件就不會報錯了。
至於為什麼不創建文件而報錯,我也沒想明白。

BufferedInputStream例子

這個例子將展示如何使用BufferedInputStream來提高文件讀取的效率。

package demo;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class BufferedStreamExample {
    public static void main(String[] args) {
        String sourcePath = "/Users/wu/studyIo/source.txt";
        BufferedInputStream bis = null;

        try {
            bis = new BufferedInputStream(new FileInputStream(sourcePath));

            int data = bis.read();

            while (data != -1) {
                System.out.print((char) data);
                data = bis.read();
            }

            System.out.println("\n文件讀取完成。");

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

運行結果:
image.png
這裏面會出現亂碼問題,原因是用的是BufferedInputStream他是字節流,一箇中文是佔3個字節,它將他分成了一個一個字節讀,就會亂碼,把BufferedInputStream換為BufferedReader字符流就可以解決亂碼問題。(要考慮文件編碼格式)

四、以對象處理流來學習序列化和反序列化

序列化:保持數據時,保持數據的值和數據類型
反序列化:恢復數據時,恢復數據的值和數據類型

package demo;

import java.io.*;

public class SerializationDemo {
    public static void main(String[] args) {
        String sourcePath = "/Users/wu/studyIo/employee.txt";

        // 序列化過程
        try (FileOutputStream fileOut = new FileOutputStream(sourcePath);
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {

            Employee emp = new Employee("John Doe", 30);
            out.writeObject(emp);
            System.out.println("Serialized data is saved in employee.ser");

        } catch (IOException i) {
            i.printStackTrace();
        }

        // 反序列化過程
        Employee emp = null;
        try (FileInputStream fileIn = new FileInputStream(sourcePath);
             ObjectInputStream in = new ObjectInputStream(fileIn)) {

            emp = (Employee) in.readObject();
            System.out.println("Deserialized Employee...");
            System.out.println("Employee : " + emp);

        } catch (IOException i) {
            i.printStackTrace();
            return;
        } catch (ClassNotFoundException c) {
            System.out.println("Employee class not found");
            c.printStackTrace();
            return;
        }
    }
}

五、補充字符轉換流,打印流和隨機訪問流

補充流

六、IO異常處理

  1. 用try-catch-finally語句塊處理異常。
  2. 類名後面添加 throws IOException 聲明可以有IO異常發生,但不做處理。

參考資料

嗶哩嗶哩 -->韓順平老師講的IO專題視頻

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.