DeepSeek Java NIO Channels 演示
·
Java NIO Channels 演示
NIO Channels 是 Java NIO 的核心组件之一,提供了比传统 I/O 更高效的数据传输方式。下面是一个完整的演示:
1. 基本通道类型演示
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
public class NIOChannelsDemo {
public static void main(String[] args) {
System.out.println("=== Java NIO Channels 演示 ===\n");
try {
// 1. 文件通道演示
fileChannelDemo();
// 2. 缓冲区演示
bufferDemo();
// 3. 文件复制对比
fileCopyComparison();
// 4. Socket通道演示(简单示例)
socketChannelDemo();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文件通道操作演示
*/
private static void fileChannelDemo() throws IOException {
System.out.println("1. 文件通道操作演示");
System.out.println("-".repeat(50));
// 创建测试文件
Path testFile = Paths.get("test_data.txt");
String content = "Java NIO Channels 演示\n" +
"第二行数据\n" +
"第三行数据\n" +
"第四行数据\n";
// 写入文件 - 使用 FileChannel
System.out.println("写入文件内容:");
System.out.println(content);
try (FileChannel writeChannel = FileChannel.open(testFile,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING)) {
ByteBuffer buffer = ByteBuffer.wrap(content.getBytes());
writeChannel.write(buffer);
System.out.println("文件写入完成");
}
// 读取文件 - 使用 FileChannel
System.out.println("\n读取文件内容:");
try (FileChannel readChannel = FileChannel.open(testFile, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = readChannel.read(buffer);
buffer.flip(); // 切换为读模式
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
System.out.println("读取字节数: " + bytesRead);
}
// 文件位置操作
System.out.println("\n文件位置操作:");
try (RandomAccessFile raf = new RandomAccessFile(testFile.toFile(), "r");
FileChannel channel = raf.getChannel()) {
System.out.println("文件大小: " + channel.size() + " 字节");
// 定位到第10个字节
channel.position(10);
ByteBuffer buffer = ByteBuffer.allocate(20);
channel.read(buffer);
buffer.flip();
System.out.print("从位置10读取的内容: ");
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
System.out.println();
}
// 清理测试文件
Files.deleteIfExists(testFile);
System.out.println();
}
/**
* 缓冲区操作演示
*/
private static void bufferDemo() {
System.out.println("2. 缓冲区操作演示");
System.out.println("-".repeat(50));
// 创建ByteBuffer
ByteBuffer buffer = ByteBuffer.allocate(50);
printBufferState("初始状态", buffer);
// 写入数据
String data = "Hello NIO!";
buffer.put(data.getBytes());
printBufferState("写入数据后", buffer);
// 切换到读模式
buffer.flip();
printBufferState("调用flip()后", buffer);
// 读取数据
System.out.print("读取的数据: ");
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
System.out.println();
printBufferState("读取数据后", buffer);
// 清空缓冲区
buffer.clear();
printBufferState("调用clear()后", buffer);
// 使用 wrap 创建缓冲区
ByteBuffer wrappedBuffer = ByteBuffer.wrap("包装的数据".getBytes());
printBufferState("包装缓冲区", wrappedBuffer);
// mark 和 reset 操作
ByteBuffer markBuffer = ByteBuffer.allocate(20);
markBuffer.put("标记测试".getBytes());
markBuffer.flip();
markBuffer.get(); // 读取一个字节
markBuffer.mark(); // 设置标记
System.out.print("\n标记后读取: ");
while (markBuffer.hasRemaining()) {
System.out.print((char) markBuffer.get());
}
markBuffer.reset(); // 重置到标记位置
System.out.print("\n重置后读取: ");
while (markBuffer.hasRemaining()) {
System.out.print((char) markBuffer.get());
}
System.out.println("\n");
}
/**
* 文件复制性能对比
*/
private static void fileCopyComparison() throws IOException {
System.out.println("3. 文件复制性能对比");
System.out.println("-".repeat(50));
// 创建测试文件
Path sourceFile = Paths.get("source_large.txt");
Path dest1 = Paths.get("dest_traditional.txt");
Path dest2 = Paths.get("dest_nio.txt");
// 生成大文件内容
StringBuilder content = new StringBuilder();
for (int i = 0; i < 10000; i++) {
content.append("这是第 ").append(i).append(" 行数据。".repeat(10)).append("\n");
}
Files.write(sourceFile, content.toString().getBytes());
System.out.println("创建测试文件大小: " + Files.size(sourceFile) + " 字节");
// 传统IO复制
long startTime = System.nanoTime();
try (InputStream in = new FileInputStream(sourceFile.toFile());
OutputStream out = new FileOutputStream(dest1.toFile())) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
long traditionalTime = System.nanoTime() - startTime;
// NIO复制
startTime = System.nanoTime();
try (FileChannel sourceChannel = FileChannel.open(sourceFile, StandardOpenOption.READ);
FileChannel destChannel = FileChannel.open(dest2,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING)) {
// 方法1: 使用transferTo (零拷贝)
sourceChannel.transferTo(0, sourceChannel.size(), destChannel);
// 方法2: 也可以使用transferFrom
// destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
}
long nioTime = System.nanoTime() - startTime;
System.out.println("传统IO复制时间: " + (traditionalTime / 1_000_000.0) + " ms");
System.out.println("NIO复制时间: " + (nioTime / 1_000_000.0) + " ms");
System.out.println("性能提升: " +
String.format("%.2f", (traditionalTime - nioTime) * 100.0 / traditionalTime) + "%");
// 验证文件相同
long sourceSize = Files.size(sourceFile);
long dest1Size = Files.size(dest1);
long dest2Size = Files.size(dest2);
System.out.println("\n文件大小验证:");
System.out.println("源文件: " + sourceSize + " 字节");
System.out.println("传统IO复制: " + dest1Size + " 字节 " +
(sourceSize == dest1Size ? "✓" : "✗"));
System.out.println("NIO复制: " + dest2Size + " 字节 " +
(sourceSize == dest2Size ? "✓" : "✗"));
// 清理文件
Files.deleteIfExists(sourceFile);
Files.deleteIfExists(dest1);
Files.deleteIfExists(dest2);
System.out.println();
}
/**
* Socket通道简单演示
*/
private static void socketChannelDemo() throws IOException {
System.out.println("4. Socket通道演示");
System.out.println("-".repeat(50));
// 注意:实际应用中需要启动服务器和客户端
System.out.println("SocketChannel 使用示例:");
System.out.println("""
// 客户端代码示例
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 8080));
// 设置为非阻塞模式
socketChannel.configureBlocking(false);
// 写入数据
ByteBuffer buffer = ByteBuffer.wrap("Hello Server".getBytes());
while (buffer.hasRemaining()) {
socketChannel.write(buffer);
}
// 服务器端代码示例
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
while (true) {
SocketChannel clientChannel = serverSocketChannel.accept();
if (clientChannel != null) {
// 处理客户端连接
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
clientChannel.read(readBuffer);
// ... 处理数据
}
}
""");
System.out.println("注意:这是一个代码示例,实际运行需要完整的服务器/客户端实现");
}
/**
* 打印缓冲区状态
*/
private static void printBufferState(String title, ByteBuffer buffer) {
System.out.printf("%-20s: capacity=%d, position=%d, limit=%d, remaining=%d\n",
title,
buffer.capacity(),
buffer.position(),
buffer.limit(),
buffer.remaining());
}
}
2. 高级通道特性演示
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
public class AdvancedChannelFeatures {
/**
* 通道间的数据传输(零拷贝)
*/
public static void transferBetweenChannels() throws IOException {
System.out.println("\n=== 通道间数据传输(零拷贝)===");
// 创建两个测试文件
Path source = Paths.get("source_transfer.txt");
Path dest = Paths.get("dest_transfer.txt");
Files.write(source, "这是通过transferTo传输的数据".getBytes());
try (FileChannel sourceChannel = FileChannel.open(source, StandardOpenOption.READ);
FileChannel destChannel = FileChannel.open(dest,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE)) {
// 使用transferTo - 更高效的文件复制
long transferred = sourceChannel.transferTo(0, sourceChannel.size(), destChannel);
System.out.println("传输的字节数: " + transferred);
}
// 读取验证
System.out.println("目标文件内容: " + new String(Files.readAllBytes(dest)));
Files.deleteIfExists(source);
Files.deleteIfExists(dest);
}
/**
* 内存映射文件演示
*/
public static void memoryMappedFileDemo() throws IOException {
System.out.println("\n=== 内存映射文件演示 ===");
Path mappedFile = Paths.get("mapped_file.txt");
String content = "内存映射文件内容\n第二行\n第三行";
// 写入文件
Files.write(mappedFile, content.getBytes());
try (FileChannel channel = FileChannel.open(mappedFile,
StandardOpenOption.READ,
StandardOpenOption.WRITE)) {
// 创建内存映射
MappedByteBuffer mappedBuffer = channel.map(
FileChannel.MapMode.READ_WRITE, 0, channel.size());
System.out.println("映射缓冲区大小: " + mappedBuffer.capacity());
// 读取内容
System.out.print("映射文件内容: ");
while (mappedBuffer.hasRemaining()) {
System.out.print((char) mappedBuffer.get());
}
System.out.println();
// 修改内容(直接在内存中修改)
mappedBuffer.position(0); // 重置位置
mappedBuffer.put("修改后的".getBytes());
// 强制同步到磁盘
mappedBuffer.force();
System.out.println("修改已同步到磁盘");
}
// 验证修改
System.out.println("文件实际内容: " + new String(Files.readAllBytes(mappedFile)));
Files.deleteIfExists(mappedFile);
}
/**
* 分散和聚集IO演示
*/
public static void scatterGatherDemo() throws IOException {
System.out.println("\n=== 分散和聚集IO演示 ===");
Path scatterFile = Paths.get("scatter_gather.txt");
try (FileChannel channel = FileChannel.open(scatterFile,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.READ)) {
// 聚集写入:将多个缓冲区的内容写入一个通道
ByteBuffer header = ByteBuffer.wrap("Header: ".getBytes());
ByteBuffer body = ByteBuffer.wrap("Body Content".getBytes());
ByteBuffer footer = ByteBuffer.wrap("\nFooter".getBytes());
ByteBuffer[] buffers = {header, body, footer};
// 写入前需要确保所有缓冲区都在正确位置
for (ByteBuffer buf : buffers) {
buf.rewind();
}
channel.write(buffers);
System.out.println("聚集写入完成");
// 分散读取:从一个通道读取数据到多个缓冲区
channel.position(0); // 重置文件位置
ByteBuffer readHeader = ByteBuffer.allocate(8);
ByteBuffer readBody = ByteBuffer.allocate(12);
ByteBuffer readFooter = ByteBuffer.allocate(7);
ByteBuffer[] readBuffers = {readHeader, readBody, readFooter};
long bytesRead = channel.read(readBuffers);
System.out.println("读取字节数: " + bytesRead);
// 打印读取的内容
System.out.print("分散读取内容: ");
for (ByteBuffer buf : readBuffers) {
buf.flip();
while (buf.hasRemaining()) {
System.out.print((char) buf.get());
}
}
System.out.println();
}
Files.deleteIfExists(scatterFile);
}
/**
* 文件锁定演示
*/
public static void fileLockingDemo() throws IOException {
System.out.println("\n=== 文件锁定演示 ===");
Path lockFile = Paths.get("lock_test.txt");
Files.write(lockFile, "测试文件锁定".getBytes());
try (FileChannel channel = FileChannel.open(lockFile,
StandardOpenOption.READ,
StandardOpenOption.WRITE)) {
// 获取独占锁
FileLock lock = channel.lock();
System.out.println("获取文件锁: " +
(lock.isShared() ? "共享锁" : "独占锁"));
System.out.println("锁的位置: " + lock.position() +
", 大小: " + lock.size());
// 在持有锁的情况下操作文件
ByteBuffer buffer = ByteBuffer.wrap("\n在锁保护下写入".getBytes());
channel.position(channel.size());
channel.write(buffer);
// 释放锁
lock.release();
System.out.println("文件锁已释放");
}
System.out.println("最终文件内容: " + new String(Files.readAllBytes(lockFile)));
Files.deleteIfExists(lockFile);
}
public static void main(String[] args) throws IOException {
System.out.println("=== Java NIO 高级特性演示 ===\n");
transferBetweenChannels();
memoryMappedFileDemo();
scatterGatherDemo();
fileLockingDemo();
}
}
3. 使用示例和最佳实践
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.*;
/**
* 实用的NIO工具类示例
*/
public class NIOUtils {
/**
* 高效的文本文件读取
*/
public static List<String> readLines(Path filePath) throws IOException {
List<String> lines = new ArrayList<>();
try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocateDirect(8192); // 使用直接缓冲区
StringBuilder lineBuilder = new StringBuilder();
byte[] lineSeparator = System.lineSeparator().getBytes();
while (channel.read(buffer) != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
char c = (char) buffer.get();
if (c == '\n') {
lines.add(lineBuilder.toString());
lineBuilder.setLength(0);
} else if (c != '\r') {
lineBuilder.append(c);
}
}
buffer.compact();
}
if (lineBuilder.length() > 0) {
lines.add(lineBuilder.toString());
}
}
return lines;
}
/**
* 高效的大文件复制
*/
public static void copyLargeFile(Path source, Path destination) throws IOException {
try (FileChannel sourceChannel = FileChannel.open(source, StandardOpenOption.READ);
FileChannel destChannel = FileChannel.open(destination,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING)) {
long position = 0;
long size = sourceChannel.size();
// 分块传输,适合超大文件
while (position < size) {
position += sourceChannel.transferTo(position, 64 * 1024 * 1024, destChannel);
}
}
}
/**
* 使用内存映射快速搜索文件
*/
public static long searchInFile(Path filePath, String searchText) throws IOException {
try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_ONLY, 0, channel.size());
byte[] searchBytes = searchText.getBytes();
long count = 0;
for (int i = 0; i <= buffer.limit() - searchBytes.length; i++) {
boolean match = true;
for (int j = 0; j < searchBytes.length; j++) {
if (buffer.get(i + j) != searchBytes[j]) {
match = false;
break;
}
}
if (match) {
count++;
}
}
return count;
}
}
/**
* 非阻塞文件监控(简单示例)
*/
public static void watchFileChanges(Path directory) throws IOException {
WatchService watchService = FileSystems.getDefault().newWatchService();
directory.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
System.out.println("开始监控目录: " + directory);
Thread watchThread = new Thread(() -> {
try {
while (true) {
WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
@SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path fileName = ev.context();
System.out.printf("事件: %s, 文件: %s\n", kind.name(), fileName);
}
if (!key.reset()) {
break;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
watchThread.setDaemon(true);
watchThread.start();
}
}
总结
NIO Channels 的主要优势:
- 更高的性能:使用缓冲区和通道减少系统调用
- 零拷贝技术:
transferTo()和transferFrom()方法 - 内存映射文件:通过
MappedByteBuffer直接操作文件 - 非阻塞IO:支持异步操作
- 分散/聚集:高效处理多个缓冲区
使用建议:
- 处理大文件时使用内存映射
- 文件复制使用
transferTo()/transferFrom() - 需要高性能时使用直接缓冲区
- 注意正确处理缓冲区的 flip/clear/rewind 操作
这个演示涵盖了 NIO Channels 的核心概念和实用技巧,可以根据具体需求选择合适的方法。
更多推荐

所有评论(0)