当前位置: 首页 > news >正文

如何在Java中使用NIO框架?

在 Java 中使用 NIO 框架(Java NIO)需掌握其核心组件(Buffer、Channel、Selector)及非阻塞 I/O 模型。以下从基础组件使用文件操作网络通信高级封装框架四个维度,结合示例详解具体用法:

一、Java NIO 核心组件基础

Java NIO 的核心是Buffer(缓冲区)Channel(通道)Selector(选择器),三者协同实现非阻塞 I/O:
  • Buffer:数据容器,用于存储待读写的数据(如 ByteBuffer、CharBuffer);
  • Channel:双向数据通道(连接数据源与 Buffer),支持非阻塞操作(如 FileChannel、SocketChannel);
  • Selector:多路复用器,让单线程监听多个 Channel 的 I/O 事件(如连接、可读、可写)。

二、NIO 文件操作(FileChannel)

FileChannel 用于文件的读写,支持阻塞 / 非阻塞模式,性能优于传统 FileInputStream/FileOutputStream。

1. 读取文件

java
 
运行
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;public class NIOFileReadExample {public static void main(String[] args) {try (// 以读写模式打开文件RandomAccessFile file = new RandomAccessFile("data.txt", "rw");// 获取文件通道FileChannel channel = file.getChannel()) {// 分配缓冲区(容量1024字节)ByteBuffer buffer = ByteBuffer.allocate(1024);// 从通道读取数据到缓冲区int bytesRead = channel.read(buffer);while (bytesRead != -1) { // -1表示读取完毕// 切换缓冲区为"读模式"(limit=position,position=0)buffer.flip();// 读取缓冲区数据(转换为字符串)String content = StandardCharsets.UTF_8.decode(buffer).toString();System.out.print(content);// 清空缓冲区(切换为"写模式",position=0,limit=capacity)buffer.clear();// 继续读取下一批数据bytesRead = channel.read(buffer);}} catch (Exception e) {e.printStackTrace();}}
}
 

2. 写入文件

java
 
运行
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;public class NIOFileWriteExample {public static void main(String[] args) {try (RandomAccessFile file = new RandomAccessFile("output.txt", "rw");FileChannel channel = file.getChannel()) {String data = "Hello Java NIO!";// 将字符串转为字节数组,写入缓冲区ByteBuffer buffer = ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8));// 从缓冲区写入通道(即写入文件)channel.write(buffer);System.out.println("数据写入完成");} catch (Exception e) {e.printStackTrace();}}
}
 

3. 文件复制(通道直接传输)

FileChannel 支持transferFrom()/transferTo()直接传输数据,无需缓冲区中转,效率更高:
java
 
运行
 
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;public class NIOFileCopyExample {public static void main(String[] args) {try (RandomAccessFile sourceFile = new RandomAccessFile("source.txt", "r");RandomAccessFile targetFile = new RandomAccessFile("target.txt", "rw");FileChannel sourceChannel = sourceFile.getChannel();FileChannel targetChannel = targetFile.getChannel()) {// 从源通道传输数据到目标通道(参数:起始位置,传输大小,目标通道)sourceChannel.transferTo(0, sourceChannel.size(), targetChannel);System.out.println("文件复制完成");} catch (Exception e) {e.printStackTrace();}}
}
 

三、NIO 网络通信(Selector + SocketChannel)

Java NIO 的核心优势是非阻塞网络通信,通过 Selector 实现单线程处理多连接,适用于高并发场景(如服务器开发)。

1. NIO 服务器端(支持多客户端连接)

java
 
运行
 
 
 
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;public class NIOServer {public static void main(String[] args) {try (// 打开Selector(多路复用器)Selector selector = Selector.open();// 打开服务器通道(ServerSocketChannel)ServerSocketChannel serverChannel = ServerSocketChannel.open()) {// 绑定端口serverChannel.bind(new InetSocketAddress(8080));// 设置为非阻塞模式(必须,否则Selector无法工作)serverChannel.configureBlocking(false);// 注册"连接事件"(OP_ACCEPT)到SelectorserverChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("NIO服务器启动,监听端口8080...");while (true) {// 阻塞等待事件触发(返回触发的事件数)int readyChannels = selector.select();if (readyChannels == 0) continue;// 获取所有触发的事件KeySet<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();// 处理"连接事件"(客户端发起连接)if (key.isAcceptable()) {ServerSocketChannel ssc = (ServerSocketChannel) key.channel();// 接受客户端连接,返回SocketChannelSocketChannel clientChannel = ssc.accept();clientChannel.configureBlocking(false);// 注册"读事件"(OP_READ)到Selector,关联一个缓冲区clientChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));System.out.println("客户端连接:" + clientChannel.getRemoteAddress());}// 处理"读事件"(客户端发送数据)else if (key.isReadable()) {SocketChannel clientChannel = (SocketChannel) key.channel();// 获取关联的缓冲区ByteBuffer buffer = (ByteBuffer) key.attachment();// 从通道读取数据到缓冲区int bytesRead = clientChannel.read(buffer);if (bytesRead == -1) {// 客户端关闭连接clientChannel.close();key.cancel();System.out.println("客户端断开连接:" + clientChannel.getRemoteAddress());continue;}// 切换缓冲区为读模式buffer.flip();// 解码数据为字符串String msg = StandardCharsets.UTF_8.decode(buffer).toString().trim();System.out.println("收到客户端消息:" + msg);// 回复客户端(可选)String response = "服务器已收到:" + msg;buffer.clear();buffer.put(response.getBytes(StandardCharsets.UTF_8));buffer.flip();clientChannel.write(buffer);// 清空缓冲区,准备下次读取buffer.clear();}// 移除已处理的事件Key(必须,否则会重复处理)keyIterator.remove();}}} catch (IOException e) {e.printStackTrace();}}
}
 

2. NIO 客户端(连接服务器并发送数据)

java
 
运行
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;public class NIOClient {public static void main(String[] args) {try (// 打开SocketChannelSocketChannel clientChannel = SocketChannel.open();Scanner scanner = new Scanner(System.in)) {// 连接服务器clientChannel.connect(new InetSocketAddress("localhost", 8080));// 设置为非阻塞模式(可选,若需异步操作)clientChannel.configureBlocking(false);ByteBuffer buffer = ByteBuffer.allocate(1024);System.out.println("已连接服务器,输入消息发送(输入exit退出):");while (true) {String msg = scanner.nextLine();if ("exit".equalsIgnoreCase(msg)) break;// 写入数据到缓冲区buffer.put(msg.getBytes(StandardCharsets.UTF_8));buffer.flip();// 发送数据到服务器clientChannel.write(buffer);buffer.clear();// 读取服务器回复(非阻塞模式需循环读取)int bytesRead = clientChannel.read(buffer);if (bytesRead > 0) {buffer.flip();String response = StandardCharsets.UTF_8.decode(buffer).toString();System.out.println("服务器回复:" + response);buffer.clear();}}} catch (IOException e) {e.printStackTrace();}}
}
 

四、使用高级 NIO 封装框架(Netty)

Java NIO 原生 API 较繁琐,实际开发中常使用Netty(基于 NIO 封装的高性能网络框架),简化开发流程:

1. Netty 服务器端示例

java
 
运行
 
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;public class NettyServer {public static void main(String[] args) throws InterruptedException {// 主线程组(接受连接)EventLoopGroup bossGroup = new NioEventLoopGroup(1);// 工作线程组(处理读写)EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 使用NIO通道.option(ChannelOption.SO_BACKLOG, 128) // 连接队列大小.childOption(ChannelOption.SO_KEEPALIVE, true) // 保持长连接.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 添加字符串编解码器pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());// 添加自定义业务处理器pipeline.addLast(new NettyServerHandler());}});// 绑定端口并启动ChannelFuture future = bootstrap.bind(8080).sync();System.out.println("Netty服务器启动,监听端口8080...");// 等待服务器关闭future.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}// 自定义业务处理器static class NettyServerHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println("收到客户端消息:" + msg);// 回复客户端ctx.writeAndFlush("服务器已收到:" + msg);}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("客户端连接:" + ctx.channel().remoteAddress());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}
}
 

2. Netty 客户端示例

java
 
运行
 
 
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;import java.util.Scanner;public class NettyClient {public static void main(String[] args) throws InterruptedException {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());pipeline.addLast(new NettyClientHandler());}});// 连接服务器ChannelFuture future = bootstrap.connect("localhost", 8080).sync();Channel channel = future.channel();System.out.println("已连接服务器,输入消息发送(输入exit退出):");Scanner scanner = new Scanner(System.in);while (true) {String msg = scanner.nextLine();if ("exit".equalsIgnoreCase(msg)) {channel.close();break;}// 发送消息channel.writeAndFlush(msg);}channel.closeFuture().sync();} finally {group.shutdownGracefully();}}static class NettyClientHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println("服务器回复:" + msg);}}
}
 

五、NIO 使用注意事项

  1. Buffer 操作:务必区分 “写模式” 和 “读模式”(通过flip()切换),避免数据读取错误;
  2. 非阻塞模式:Channel 需设置为configureBlocking(false)才能配合 Selector 使用;
  3. Selector 事件处理:处理完事件后必须移除SelectionKeykeyIterator.remove()),否则会重复触发;
  4. 资源释放:Channel、Selector 需通过try-with-resources或手动关闭,避免资源泄漏;
  5. 高并发场景:优先使用 Netty 等封装框架,避免原生 NIO 的复杂细节。

总结

Java NIO 通过 Buffer、Channel、Selector 实现非阻塞 I/O,适用于文件操作和高并发网络通信。原生 API 需手动管理缓冲区和事件,而 Netty 等框架封装了底层细节,大幅提升开发效率。根据场景选择:简单文件操作可用原生 FileChannel,高并发网络开发优先用 Netty。
http://www.jsqmd.com/news/53154/

相关文章:

  • 返回值类
  • 为什么说白瑞芳是最适合基础巩固的高中数学老师?
  • 全自动滤水器厂家推荐:连云港华博与博璟源的专业之选
  • 全自动工业滤水器厂家推荐:连云港华博与博璟源的专业之选
  • 美容院选择皮肤检测仪的5大标准:安德颜析MINI如何满足专业需求
  • 2025年11月漱口水品牌推荐列表与市场口碑分析报告
  • 完整教程:集群环境安装与部署 Hadoop
  • [题解]考前一些贪心技巧题
  • mysql查看binlog, 追溯历史
  • 实用指南:Jenkins Pipeline 快速开始
  • 2025年下半年特氟龙喷涂、聚四氟乙烯喷涂、陶瓷喷涂、碳化钨喷涂、聚四氟乙烯管道设备厂家口碑推荐
  • 两款开源PLC软件推荐,ARMxy系列完美适配!
  • 251127
  • 2025年下半年特氟龙喷涂、聚四氟乙烯喷涂、陶瓷喷涂、碳化钨喷涂、聚四氟乙烯管道设备厂家综合评估与选购指南
  • 2025年下半年菜籽油/粮油批发/植物油/食用油批发厂家口碑前五推荐
  • 成都动力无限:深耕十五载,以专业短视频代运营赋能企业增长
  • 2025年下半年特氟龙喷涂、聚四氟乙烯喷涂、陶瓷喷涂、碳化钨喷涂、聚四氟乙烯管道设备厂家综合推荐指南
  • android studio,java 语言。新建了任务,在哪儿设置 app 的名字和 logo。
  • 3 天从 0 入门 SQL:交易所 Market Surveillance 实战速成(Wash Trading / Spoofing / Pump Dump)
  • 保姆级教程!PaddleOCR-VL 私有化部署全流程,109 种语言 SOTA 模型直接用
  • 2025年下半年拖车绳/三股绳/拖拉绳/弹力绳工厂 top 5 推荐
  • 怎样减少库存对资金的占用?企业老板最该先解决的,其实就是这三件事
  • 容器终端常用命令
  • 深入解析:批量替换文件内容麻烦?Windows小工具5步搞定,效率提升80%
  • Raney 引理小记
  • 2026年石家庄/邯郸/邢台/保定/沧州/廊坊/衡水农村自建房推荐榜,图南建房宝领衔 六家实力公司赋能乡村宜居生活
  • 2025年下半年拖车绳/三股绳/拖拉绳/弹力绳厂家前五推荐
  • 头大的内存泄漏
  • 金蝶ERP制造业行业实施专家榜:专精特新企业如何选择行业经验丰富的服务商?
  • 清理谷歌浏览器垃圾文件 Chrome “User Data” - 教程