首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java I/O 體系全景:從傳統流到 NIO 零拷貝原理

     編輯:Java 相關知識

Java I/O 是後端開發的核心基本功。本文梳理 java.io 傳統流體系、java.nio 非阻塞模型、零拷貝與內存映射底層原理,構建完整知識圖譜。

一、傳統流(java.io)體系

1. 核心抽象

  • 字節流:InputStream/OutputStream — 處理二進制數據(圖片、視頻、序列化對象)。
  • 字符流:Reader/Writer — 處理文本,內部按 UTF-16(char)處理,涉及編解碼。

2. 主要實現類

類型節點流(直達數據源)處理流/裝飾器(增強功能)
字節輸入FileInputStream, ByteArrayInputStream, PipedInputStreamBufferedInputStream, DataInputStream, ObjectInputStream
字節輸出FileOutputStream, ByteArrayOutputStream, PipedOutputStreamBufferedOutputStream, DataOutputStream, ObjectOutputStream
字符輸入FileReader, CharArrayReader, StringReader, PipedReaderBufferedReader, InputStreamReader(橋接), LineNumberReader
字符輸出FileWriter, CharArrayWriter, StringWriter, PipedWriterBufferedWriter, OutputStreamWriter(橋接), PrintWriter

裝飾器模式:new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")) — 層層包裝,職責單一。

3. 標準流

  • System.in(標準輸入/鍵盤) → InputStream
  • System.out(標準輸出/屏幕) → PrintStream
  • System.err(標準錯誤/屏幕) → PrintStream

二、NIO(New I/O / Non-blocking I/O)核心

JDK 1.4 引入,解決高併發下線程阻塞問題。

1. 三大核心組件

  • Buffer:容器(位置、限制、容量、標記),ByteBuffer 最常用;支援直接內存(allocateDirect)減少堆外拷貝。
  • Channel:雙向通道(FileChannel, SocketChannel, ServerSocketChannel, DatagramChannel),數據只能 Buffer↔Channel 流動。
  • Selector:多路複用器,單線程管理成千上萬 Channel,事件驅動(OP_READ, OP_WRITE, OP_CONNECT, OP_ACCEPT)。

2. 零拷貝與內存映射

傳統讀寫:磁盘 → 內核緩衝區 → 用戶緩衝區 → 內核 Socket 緩衝區 → 協議棧(4 次拷貝,2 次上下文切換)。

FileChannel.transferTo():內核空間直接 DMA 拷貝到 Socket 緩衝區,避免用戶態拷貝(mmap 或 sendfile 系統調用)。

MappedByteBuffer:fileChannel.map(MapMode.READ_ONLY, 0, size) 將文件映射到虛擬內存,頁面缺失時由 OS 自動載入,適合大文件隨機訪問。

3. 文件鎖

FileLock lock = fileChannel.lock(start, length, shared); // 共享/獨占鎖,跨進程可見
lock.release();

三、典型使用模式

// 1. 緩衝讀取文本
try (BufferedReader br = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
    br.lines().forEach(System.out::println);
}

// 2. 二進制拷貝(NIO 快速)
try (FileChannel in = FileChannel.open(src, StandardOpenOption.READ);
     FileChannel out = FileChannel.open(dst, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
    in.transferTo(0, in.size(), out);
}

// 3. 非阻塞 Server
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open().bind(new InetSocketAddress(8080));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
    for (SelectionKey key : selector.selectedKeys()) { /* handle */ }
}

四、選型建議

  • 低併發、順序讀寫小文件 → 傳統流(代碼簡單)。
  • 高併發網絡服務、大文件傳輸、零拷貝需求 → NIO/Netty。
  • 需隨機訪問大文件 → MappedByteBuffer / RandomAccessFile。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved