Java IO 与 NIO 的区别与使用
Java IO 与 NIO 的区别与使用
Java IO (传统IO)
特点
- 面向流(Stream Oriented):数据通过流的方式传输
- 阻塞式IO(BIO):读写操作会阻塞线程直到操作完成
- 同步处理:每个连接需要一个线程处理
基本组件
// 字节流
InputStream inputStream = new FileInputStream("file.txt");
OutputStream outputStream = new FileOutputStream("output.txt");
// 字符流
Reader reader = new FileReader("file.txt");
Writer writer = new FileWriter("output.txt");
使用示例
// 传统IO文件读取示例
public class TraditionalIOExample {
public void readFile() throws IOException {
FileInputStream fis = new FileInputStream("data.txt");
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
// 处理数据
processData(buffer, bytesRead);
}
fis.close();
}
}
Java NIO (New IO/Non-blocking IO)
特点
- 面向缓冲区(Buffer Oriented):数据通过Buffer进行读写
- 非阻塞式IO:支持非阻塞模式,提高并发性能
- 选择器(Selector):一个线程可以管理多个连接
- 通道(Channel):支持双向数据传输
核心组件
- Buffer(缓冲区)
// 创建缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
CharBuffer charBuffer = CharBuffer.allocate(1024);
// Buffer操作
buffer.put("Hello".getBytes()); // 写入数据
buffer.flip(); // 切换到读模式
buffer.get(data); // 读取数据
buffer.clear(); // 清空缓冲区
- Channel(通道)
// 文件通道示例
FileInputStream fis = new FileInputStream("data.txt");
FileChannel channel = fis.getChannel();
// 从通道读取数据到缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer);
- Selector(选择器)
// 创建选择器
Selector selector = Selector.open();
// 注册通道到选择器
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
NIO使用示例
public class NIOExample {
public void readFile() throws IOException {
RandomAccessFile file = new RandomAccessFile("data.txt", "r");
FileChannel channel = file.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer);
while (bytesRead != -1) {
buffer.flip(); // 切换到读模式
while (buffer.hasRemaining()) {
// 处理数据
System.out.print((char) buffer.get());
}
buffer.clear(); // 清空缓冲区准备下一次读取
bytesRead = channel.read(buffer);
}
file.close();
}
}
NIO服务器示例
public class NIOServer {
public void startServer() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // 阻塞直到有事件发生
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
handleAccept(key, selector);
} else if (key.isReadable()) {
handleRead(key);
}
keyIterator.remove();
}
}
}
private void handleAccept(SelectionKey key, Selector selector) throws IOException {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
}
private void handleRead(SelectionKey key) throws IOException {
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = clientChannel.read(buffer);
// 处理读取的数据
}
}
主要区别对比
特性 | Java IO | Java NIO |
---|---|---|
处理方式 | 面向流 | 面向缓冲区 |
IO模式 | 阻塞IO | 非阻塞IO |
并发处理 | 一个连接一个线程 | 一个线程处理多个连接 |
数据传输 | 单向 | 双向 |
应用场景 | 连接数较少,对延迟敏感 | 连接数多,对并发要求高 |
适用场景
Java IO 适用场景
- 连接数较少的应用
- 对延迟敏感的应用
- 简单的文件读写操作
- 传统的服务器应用
Java NIO 适用场景
- 高并发服务器应用
- 需要处理大量连接
- 对性能要求较高的应用
- 聊天服务器、游戏服务器等
性能优化建议
- 合理使用Buffer大小:根据实际数据量调整Buffer大小
- 避免频繁创建Buffer:复用Buffer对象
- 正确管理资源:及时关闭Channel和释放资源
- 选择合适的Channel类型:根据需求选择FileChannel、SocketChannel等
Java NIO提供了更高效的IO处理方式,特别适用于高并发场景,但使用复杂度相对较高,需要深入理解其工作机制。