本文目录导读:

下面我为你详细讲解Java NIO(New I/O)的完整案例,包含核心概念和实际代码示例。
Java NIO核心组件
Java NIO主要包含三大核心组件:
- Channel(通道):数据传输的载体
- Buffer(缓冲区):数据存储的容器
- Selector(选择器):多路复用器,监控多个通道
基础案例:文件复制
1 使用FileChannel复制文件
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileChannelDemo {
public static void main(String[] args) {
String sourceFile = "source.txt";
String targetFile = "target.txt";
try {
copyFile(sourceFile, targetFile);
System.out.println("文件复制成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 使用FileChannel复制文件
*/
public static void copyFile(String source, String target) throws IOException {
// 打开文件通道
Path sourcePath = Paths.get(source);
Path targetPath = Paths.get(target);
try (FileChannel sourceChannel = FileChannel.open(sourcePath, StandardOpenOption.READ);
FileChannel targetChannel = FileChannel.open(targetPath, StandardOpenOption.WRITE,
StandardOpenOption.CREATE)) {
// 创建缓冲区(大小为8KB)
ByteBuffer buffer = ByteBuffer.allocate(8192);
// 从源通道读取数据到缓冲区
while (sourceChannel.read(buffer) != -1) {
// 切换为读模式
buffer.flip();
// 将缓冲区数据写入目标通道
while (buffer.hasRemaining()) {
targetChannel.write(buffer);
}
// 清空缓冲区,准备下一次读取
buffer.clear();
}
}
}
}
2 使用transferTo实现零拷贝
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class ZeroCopyDemo {
public static void main(String[] args) throws IOException {
String sourceFile = "large_file.zip";
String targetFile = "large_file_copy.zip";
// 零拷贝方式复制文件
try (FileChannel sourceChannel = FileChannel.open(Paths.get(sourceFile), StandardOpenOption.READ);
FileChannel targetChannel = FileChannel.open(Paths.get(targetFile), StandardOpenOption.WRITE,
StandardOpenOption.CREATE)) {
long position = 0;
long size = sourceChannel.size();
// 使用transferTo实现零拷贝
while (position < size) {
position += sourceChannel.transferTo(position, size - position, targetChannel);
}
System.out.println("零拷贝复制完成!");
}
}
}
Socket通信案例
1 阻塞式Socket通信
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class BlockingSocketDemo {
// 服务器端
public static class Server {
public static void main(String[] args) throws IOException {
int port = 8080;
// 创建ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
System.out.println("服务器启动,监听端口:" + port);
// 创建线程池处理客户端请求
ExecutorService executor = Executors.newFixedThreadPool(10);
while (true) {
// 接受客户端连接(阻塞)
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("客户端连接:" + socketChannel.getRemoteAddress());
// 为每个客户端创建独立线程
executor.submit(() -> handleClient(socketChannel));
}
}
private static void handleClient(SocketChannel socketChannel) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
// 读取客户端发送的数据
while (socketChannel.read(buffer) != -1) {
buffer.flip();
// 将数据转换字符串并打印
String message = new String(buffer.array(), 0, buffer.limit());
System.out.println("收到客户端消息:" + message);
// 回显消息给客户端
String response = "服务器已收到:" + message;
buffer.clear();
buffer.put(response.getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 客户端
public static class Client {
public static void main(String[] args) throws IOException {
// 连接服务器
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 8080));
// 发送多条消息
String[] messages = {"Hello", "World", "Java NIO"};
for (String message : messages) {
// 发送消息
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(message.getBytes());
buffer.flip();
socketChannel.write(buffer);
// 读取响应
buffer.clear();
socketChannel.read(buffer);
buffer.flip();
String response = new String(buffer.array(), 0, buffer.limit());
System.out.println("服务器响应:" + response);
Thread.sleep(1000);
}
socketChannel.close();
}
}
}
2 非阻塞式Socket通信(Selector多路复用)
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class NonBlockingSocketDemo {
public static void main(String[] args) throws IOException {
int port = 8090;
Selector selector = Selector.open();
// 创建ServerSocketChannel并设置为非阻塞
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(port));
// 注册接受连接事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("非阻塞式服务器启动,端口:" + port);
// 存储客户端数据处理任务
ConcurrentHashMap<SocketChannel, StringBuilder> clientData = new ConcurrentHashMap<>();
while (true) {
// 阻塞直到有事件发生
selector.select();
// 获取所有事件
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
// 处理不同的事件
if (key.isAcceptable()) {
// 接受连接
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
// 注册读事件
client.register(selector, SelectionKey.OP_READ);
System.out.println("客户端连接:" + client.getRemoteAddress());
clientData.put(client, new StringBuilder());
} else if (key.isReadable()) {
// 读取数据
handleRead(key, clientData);
}
}
}
}
private static void handleRead(SelectionKey key,
ConcurrentHashMap<SocketChannel, StringBuilder> clientData) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
int bytesRead = client.read(buffer);
if (bytesRead == -1) {
// 连接关闭
clientData.remove(client);
client.close();
key.cancel();
return;
}
buffer.flip();
String data = new String(buffer.array(), 0, buffer.limit());
System.out.println("收到数据:" + data);
// 处理数据
if (data.startsWith("START:")) {
String fileName = data.substring(6);
clientData.get(client).append("文件开始接收:" + fileName + "\n");
// 发送确认
sendResponse(client, "文件传输开始");
} else if (data.equals("END")) {
clientData.get(client).append("文件传输结束");
String fullData = clientData.get(client).toString();
System.out.println("完整文件数据:\n" + fullData);
clientData.put(client, new StringBuilder());
} else {
clientData.get(client).append(data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void sendResponse(SocketChannel client, String message) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(message.getBytes());
buffer.flip();
client.write(buffer);
}
}
文件映射和内存映射
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class MappedFileDemo {
public static void main(String[] args) throws IOException {
// 创建文件
Path filePath = Paths.get("mapped_file.txt");
Files.deleteIfExists(filePath);
Files.createFile(filePath);
// 内存映射写入
writeWithMapping(filePath);
// 内存映射读取
readWithMapping(filePath);
}
/**
* 使用内存映射写入文件
*/
public static void writeWithMapping(Path filePath) throws IOException {
try (FileChannel channel = FileChannel.open(filePath,
StandardOpenOption.READ,
StandardOpenOption.WRITE)) {
// 映射到内存(大小为文件大小或更大)
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
// 写入数据
String content = "这是一个内存映射文件示例\n";
buffer.put(content.getBytes());
buffer.put("Java NIO内存映射".getBytes());
System.out.println("内存映射写入完成");
}
}
/**
* 使用内存映射读取文件
*/
public static void readWithMapping(Path filePath) throws IOException {
try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {
// 映射到只读模式
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
// 读取数据
byte[] data = new byte[buffer.limit()];
buffer.get(data);
String content = new String(data);
System.out.println("读取内容:\n" + content);
}
}
}
完整示例:NIO文件上传下载系统
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class FileTransferSystem {
// 服务器端
public static class FileServer {
private static Map<SocketChannel, FileTransferState> transfers = new HashMap<>();
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(8081));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("文件服务器启动...");
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
// 处理连接请求
if (key.isAcceptable()) {
handleAccept(key);
}
// 处理读取事件
if (key.isReadable()) {
handleRead(key);
}
}
}
}
private static void handleAccept(SelectionKey key) throws IOException {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
// 初始化传输状态
FileTransferState state = new FileTransferState();
transfers.put(client, state);
System.out.println("客户端连接:" + client.getRemoteAddress());
}
private static void handleRead(SelectionKey key) {
SocketChannel client = (SocketChannel) key.channel();
FileTransferState state = transfers.get(client);
ByteBuffer buffer = ByteBuffer.allocate(8192);
try {
int bytesRead = client.read(buffer);
if (bytesRead == -1) {
// 连接关闭
transfers.remove(client);
client.close();
key.cancel();
return;
}
buffer.flip();
// 处理收到的数据
while (buffer.hasRemaining()) {
state.processData(buffer);
}
} catch (IOException e) {
try {
client.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
// 文件传输状态管理器
static class FileTransferState {
private String fileName;
private long fileSize;
private long receivedSize;
private Path outputPath;
private FileChannel outputChannel;
private boolean isReceiving;
public void processData(ByteBuffer buffer) throws IOException {
// 如果还没有收到文件名,首先解析文件名
if (!isReceiving) {
byte[] header = new byte[Math.min(buffer.limit(), 256)];
buffer.get(header, 0, header.length);
String headerStr = new String(header).trim();
if (headerStr.contains(":")) {
fileName = headerStr.split(":")[0];
fileSize = Long.parseLong(headerStr.split(":")[1]);
receivedSize = 0;
// 创建输出文件
outputPath = Paths.get("uploads", fileName);
Files.createDirectories(outputPath.getParent());
outputChannel = FileChannel.open(outputPath,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
isReceiving = true;
System.out.println("开始接收文件:" + fileName + ",大小:" + fileSize);
}
}
// 接收文件数据
if (isReceiving && buffer.hasRemaining()) {
outputChannel.write(buffer);
receivedSize += buffer.limit();
// 检查是否接收完成
if (receivedSize >= fileSize) {
outputChannel.close();
System.out.println("文件接收完成:" + fileName);
isReceiving = false;
}
}
}
}
}
// 客户端
public static class FileClient {
public static void main(String[] args) {
String serverIp = "localhost";
int serverPort = 8081;
String filePath = "test.txt";
try {
sendFile(serverIp, serverPort, filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendFile(String serverIp, int serverPort, String filePath) throws IOException {
// 连接服务器
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(serverIp, serverPort));
// 打开文件
Path file = Paths.get(filePath);
long fileSize = Files.size(file);
FileChannel fileChannel = FileChannel.open(file, StandardOpenOption.READ);
// 发送文件头信息
String header = file.getFileName() + ":" + fileSize;
ByteBuffer headerBuffer = ByteBuffer.wrap(header.getBytes());
socketChannel.write(headerBuffer);
// 发送文件数据
ByteBuffer buffer = ByteBuffer.allocate(8192);
while (fileChannel.read(buffer) != -1) {
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}
// 等待服务器处理
Thread.sleep(1000);
fileChannel.close();
socketChannel.close();
System.out.println("文件发送完成");
}
}
}
最佳实践建议
1 缓冲区管理
public class BufferManagementDemo {
// 动态调整缓冲区大小
public static ByteBuffer createOptimalBuffer(long fileSize) {
int optimalSize = 8192;
if (fileSize < 1024) {
optimalSize = 1024;
} else if (fileSize < 1024 * 1024) {
optimalSize = 8192;
} else if (fileSize < 1024 * 1024 * 100) {
optimalSize = 65536;
} else {
optimalSize = 1048576; // 1MB for large files
}
return ByteBuffer.allocate(optimalSize);
}
// 使用直接缓冲区提高性能
public static ByteBuffer createDirectBuffer(int size) {
return ByteBuffer.allocateDirect(size);
}
// 切片和复制
public static void bufferOperations() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 创建切片
ByteBuffer slice = buffer.slice();
// 复制(只复制内容和位置,不共享数据)
ByteBuffer duplicate = buffer.duplicate();
// 读取指定位置数据
buffer.position(100);
byte[] data = new byte[50];
buffer.get(data);
}
}
2 异常处理和资源管理
public class NIOExceptionHandling {
public static void safeChannelOperation() {
FileChannel channel = null;
try {
channel = FileChannel.open(Paths.get("test.txt"), StandardOpenOption.READ);
// 操作通道
} catch (IOException e) {
System.err.println("IO操作失败:" + e.getMessage());
e.printStackTrace();
} finally {
// 确保资源关闭
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 推荐使用try-with-resources
public static void tryWithResourcesDemo() {
try (FileChannel channel = FileChannel.open(Paths.get("test.txt"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
} catch (IOException e) {
System.err.println("IO操作失败:" + e.getMessage());
}
}
}
性能对比
| 操作类型 | 传统IO | Java NIO | 适用场景 |
|---|---|---|---|
| 文件复制 | 逐字节/逐行 | 缓冲区+零拷贝 | 大文件处理 |
| Socket通信 | 阻塞式 | 非阻塞+多路复用 | 高并发服务器 |
| 文件操作 | 大量系统调用 | 内存映射 | 文件处理 |
| 缓冲区 | 自动管理 | 手动控制 | 需要精细控制性能 |
Java NIO相比传统IO提供了:
- 非阻塞模式:支持高并发
- 缓冲区操作:更细粒度的控制
- Selector多路复用:单线程处理多个连接
- 零拷贝技术:提高大文件传输性能
在实际应用中,需要根据具体场景选择合适的方案:
- 简单文件操作:传统IO
- 高并发网络服务:NIO + Selector
- 大文件处理:内存映射
- 频繁IO操作:NIO缓冲区
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播