NIO、BIO、AIO區別

N1ce2cu發表於2024-08-01

BIO 全稱 Block-IO 是一種同步且阻塞的通訊模式。是一個比較傳統的通訊方式,模式簡單,使用方便。但併發處理能力低,通訊耗時,依賴網速。

Java NIO,全程 Non-Block IO ,是 Java SE 1.4 版以後,針對網路傳輸效能最佳化的新功能。是一種非阻塞同步的通訊模式。

NIO 與原來的 I/O 有同樣的作用和目的, 他們之間最重要的區別是資料打包和傳輸的方式。原來的 I/O 以流的方式處理資料,而 NIO 以塊的方式處理資料。

面向流的 I/O 系統一次一個位元組地處理資料。一個輸入流產生一個位元組的資料,一個輸出流消費一個位元組的資料。

面向塊的 I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個資料塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。

Java AIO,全稱 Asynchronous IO,是非同步非阻塞的 IO。是一種非阻塞非同步的通訊模式。

在 NIO 的基礎上引入了新的非同步通道的概念,並提供了非同步檔案通道和非同步套接字通道的實現。

區別


BIO (Blocking I/O):同步阻塞 I/O 模式。

NIO (New I/O):同步非阻塞模式。

AIO (Asynchronous I/O):非同步非阻塞 I/O 模型。

適用場景

BIO 方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4 以前的唯一選擇,但程式直觀簡單易理解。

NIO 方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中,程式設計比較複雜,JDK1.4 開始支援。

AIO 方式適用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫 OS 參與併發操作,程式設計比較複雜,JDK7 開始支援。

使用方式

public class BioFileDemo {
    public static void main(String[] args) {
        BioFileDemo demo = new BioFileDemo();
        demo.writeFile();
        demo.readFile();
    }

    // 使用 BIO 寫入檔案
    public void writeFile() {
        String filename = "xx.txt";
        try {
            FileWriter fileWriter = new FileWriter(filename);
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            bufferedWriter.write("學程式設計就上技術派");
            bufferedWriter.newLine();

            System.out.println("寫入完成");
            bufferedWriter.close();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 使用 BIO 讀取檔案
    public void readFile() {
        String filename = "xx.txt";
        try {
            FileReader fileReader = new FileReader(filename);
            BufferedReader bufferedReader = new BufferedReader(fileReader);

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println("讀取的內容: " + line);
            }

            bufferedReader.close();
            fileReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class NioFileDemo {
    public static void main(String[] args) {
        NioFileDemo demo = new NioFileDemo();
        demo.writeFile();
        demo.readFile();
    }

    // 使用 NIO 寫入檔案
    public void writeFile() {
        Path path = Paths.get("cc.txt");
        try {
            FileChannel fileChannel = FileChannel.open(path, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE));

            ByteBuffer buffer = StandardCharsets.UTF_8.encode("hh");
            fileChannel.write(buffer);

            System.out.println("寫入完成");
            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 使用 NIO 讀取檔案
    public void readFile() {
        Path path = Paths.get("xx.txt");
        try {
            FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            int bytesRead = fileChannel.read(buffer);
            while (bytesRead != -1) {
                buffer.flip();
                System.out.println("讀取的內容: " + StandardCharsets.UTF_8.decode(buffer));
                buffer.clear();
                bytesRead = fileChannel.read(buffer);
            }

            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class AioDemo {

    public static void main(String[] args) {
        AioDemo demo = new AioDemo();
        demo.writeFile();
        demo.readFile();
    }

    // 使用 AsynchronousFileChannel 寫入檔案
    public void writeFile() {
        // 使用 Paths.get() 獲取檔案路徑
        Path path = Paths.get("xx.txt");
        try {
            // 用 AsynchronousFileChannel.open() 開啟檔案通道,指定寫入和建立檔案的選項。
            AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);

            // 將要寫入的字串("學程式設計就上技術派")轉換為 ByteBuffer。
            ByteBuffer buffer = StandardCharsets.UTF_8.encode("學程式設計就上技術派");
            // 呼叫 fileChannel.write() 方法將 ByteBuffer 中的內容寫入檔案。這是一個非同步操作,因此需要使用 Future 物件等待寫入操作完成。
            Future<Integer> result = fileChannel.write(buffer, 0);
            // 等待寫操作完成
            result.get();

            System.out.println("寫入完成");
            fileChannel.close();
        } catch (IOException | InterruptedException | java.util.concurrent.ExecutionException e) {
            e.printStackTrace();
        }
    }

    // 使用 AsynchronousFileChannel 讀取檔案
    public void readFile() {
        Path path = Paths.get("xx.txt");
        try {
            // 指定讀取檔案的選項。
            AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
            // 建立一個 ByteBuffer,用於儲存從檔案中讀取的資料。
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            // 呼叫 fileChannel.read() 方法從檔案中非同步讀取資料。該方法接受一個 CompletionHandler 物件,用於處理非同步操作完成後的回撥。
            fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    // 在 CompletionHandler 的 completed() 方法中,翻轉 ByteBuffer(attachment.flip()),然後使用 Charset.forName("UTF-8").decode() 將其解碼為字串並列印。最後,清空緩衝區並關閉檔案通道。
                    attachment.flip();
                    System.out.println("讀取的內容: " + StandardCharsets.UTF_8.decode(attachment));
                    attachment.clear();
                    try {
                        fileChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    // 如果非同步讀取操作失敗,CompletionHandler 的 failed() 方法將被呼叫,列印錯誤資訊。
                    System.out.println("讀取失敗");
                    exc.printStackTrace();
                }
            });

            // 等待非同步操作完成
            Thread.sleep(1000);

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

相關文章