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

Java NIO 核心精講:Channel 與 Buffer 深度解析與實戰代碼

     編輯:Java 綜合教學

Java NIO 核心精講:Channel 與 Buffer 深度解析與實戰代碼

Java NIO(New I/O)以 Channel(通道) 與 Buffer(緩衝區) 為核心抽象,實現了高效、非阻塞的 I/O 操作。不同於傳統 BIO 的流式處理,NIO 採用「通道-緩衝區」雙向數據傳輸模型:數據總是從 Channel 讀入 Buffer,或從 Buffer 寫入 Channel。本文系統梳理兩大核心組件原理、關鍵 API、典型應用場景,並附帶完整可運行代碼。

一、Channel(通道)詳解

Channel 模擬傳統 I/O 中的「連接」,但具備雙向性、非阻塞性:

  • 雙向傳輸:同一 Channel 可同時支援讀/寫
  • Buffer 交互:數據不直接操作 Channel,必須經由 Buffer
  • 非阻塞模式:配合 Selector 實現多路複用

FileChannel 典型用法

FileChannel 是文件 I/O 的主力通道,獲取途徑三種:

  1. FileInputStream.getChannel()(唯讀)
  2. FileOutputStream.getChannel()(唯寫)
  3. RandomAccessFile.getChannel()(讀寫,支援隨機定位)
代碼範例:多來源獲取 Channel 並讀寫
package com.pichen.io;
import java.nio.*;
import java.nio.channels.*;
import java.io.*;

public class GetChannel {
    private static final int BSIZE = 1024;
    public static void main(String[] args) throws Exception {
        // 1. FileOutputStream 寫入
        FileOutputStream fos = new FileOutputStream("data.txt");
        FileChannel fc = fos.getChannel();
        fc.write(ByteBuffer.wrap("Some text ".getBytes()));
        fos.close();

        // 2. RandomAccessFile 追加
        RandomAccessFile raf = new RandomAccessFile("data.txt", "rw");
        fc = raf.getChannel();
        fc.position(fc.size()); // 定位末尾
        fc.write(ByteBuffer.wrap("Some more".getBytes()));
        raf.close();

        // 3. FileInputStream 讀取
        FileInputStream fis = new FileInputStream("data.txt");
        fc = fis.getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip(); // 切換讀模式
        while (buff.hasRemaining()) {
            System.out.print((char) buff.get());
        }
        fis.close();
    }
}

高效文件複製:transferTo/transferFrom 零拷貝

NIO 提供 transferTo()/transferFrom() 直接在內核態傳輸數據,避免用戶態拷貝,大文件複製效能提升數倍:

FileChannel src = new FileInputStream("src.jpg").getChannel();
FileChannel dest = new FileOutputStream("dest.jpg").getChannel();
src.transferTo(0, src.size(), dest); // 一行搞定

二、Buffer(緩衝區)核心機制

Buffer 是固定大小的容器,內部維護四個關鍵指標:

屬性含義
capacity固定容量,不可變
position下一個讀寫位置索引
limit讀模式:可讀數據上限;寫模式:等於 capacity
mark標記位置,配合 reset() 使用

核心操作方法

  • flip():寫→讀模式切換(limit=position, position=0)
  • clear():重置為寫模式(position=0, limit=capacity),不清空數據
  • compact():未讀數據前移,保留未讀內容,適用於「讀一些、寫一些」場景

Buffer 類型體系

針對基本類型提供對應實現:

  • ByteBuffer(最常用,支援直接內存 allocateDirect)
  • MappedByteBuffer(記憶體映射文件,大文件隨機訪問神器)
  • CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer, DoubleBuffer
代碼範例:完整讀寫循環
RandomAccessFile raf = new RandomAccessFile("data.txt", "rw");
FileChannel fc = raf.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);

while (fc.read(buf) != -1) {
    buf.flip();           // 準備讀取
    while (buf.hasRemaining()) {
        System.out.print((char) buf.get());
    }
    buf.compact();        // 未讀數據前移,準備下輪寫入
}
raf.close();

三、實戰模式總結

  1. 讀數據:channel.read(buffer) → buffer.flip() → buffer.get() → buffer.clear()/compact()
  2. 寫數據:buffer.put() → buffer.flip() → channel.write(buffer) → buffer.clear()
  3. 散聚/聚集 I/O:channel.read(Buffer[]) / channel.write(Buffer[]) 實現多 Buffer 組合操作

四、效能調優關鍵點

  • 直接緩衝區:ByteBuffer.allocateDirect() 分配堆外內存,減少 GC 壓力,適合長生命周期、大數據量場景
  • 內存映射:FileChannel.map(MapMode.READ_WRITE, 0, size) 讓 OS 虛擬內存管理文件,超大文件隨機讀寫首選
  • 零拷貝:transferTo() 利用 DMA 引擎,網絡傳輸(如 Netty)大量使用
參考資源:Java NIO 系列教程(ifeve)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved