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):支持双向数据传输

核心组件

  1. Buffer(缓冲区)
// 创建缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
CharBuffer charBuffer = CharBuffer.allocate(1024);

// Buffer操作
buffer.put("Hello".getBytes());  // 写入数据
buffer.flip();                   // 切换到读模式
buffer.get(data);                // 读取数据
buffer.clear();                  // 清空缓冲区
  1. Channel(通道)
// 文件通道示例
FileInputStream fis = new FileInputStream("data.txt");
FileChannel channel = fis.getChannel();

// 从通道读取数据到缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer);
  1. 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 适用场景

  • 高并发服务器应用
  • 需要处理大量连接
  • 对性能要求较高的应用
  • 聊天服务器、游戏服务器等

性能优化建议

  1. 合理使用Buffer大小:根据实际数据量调整Buffer大小
  2. 避免频繁创建Buffer:复用Buffer对象
  3. 正确管理资源:及时关闭Channel和释放资源
  4. 选择合适的Channel类型:根据需求选择FileChannel、SocketChannel等

Java NIO提供了更高效的IO处理方式,特别适用于高并发场景,但使用复杂度相对较高,需要深入理解其工作机制。

posted @ 2025-08-26 21:53  一刹流云散  阅读(8)  评论(0)    收藏  举报