使用Java NIO进行文件操作、网络通信和多路复用的案例

Java NIO(New Input/Output)是Java提供的一种新的I/O操作方式,相较于传统的Java I/O API,它能够更加高效地处理大量的并发连接。本文将详细介绍Java NIO的核心组件,包括Channel、Buffer和Selector,以及其他一些辅助类和接口。

一、Channel(通道)

Channel是Java NIO中的核心组件之一,类似于传统的IO流,负责读写数据。不同的是,Channel可以同时进行读写操作,而传统的IO流只能单向进行读或写。Channel提供了多种实现类,常用的有FileChannel(文件通道)、SocketChannel(网络套接字通道)、ServerSocketChannel(网络监听套接字通道)等。

1. FileChannel

FileChannel是用于文件操作的通道,可以读取和写入文件。它的常用方法有read()、write()、position()等。例如,可以通过FileChannel读取文件的内容:

ByteBuffer buffer = ByteBuffer.allocate(1024);
FileChannel channel = new FileInputStream("file.txt").getChannel();while (channel.read(buffer) != -1) {buffer.flip();// 处理读取到的数据buffer.clear();
}channel.close();

2. SocketChannel和ServerSocketChannel

SocketChannel和ServerSocketChannel是用于网络操作的通道。SocketChannel负责与单个客户端进行通信,而ServerSocketChannel用于监听客户端的连接请求。

SocketChannel的常用方法有connect()、read()、write()等。例如,可以通过SocketChannel连接到服务器并发送数据:

SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("localhost", 8080));String message = "Hello Server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
channel.write(buffer);channel.close();

ServerSocketChannel的常用方法有bind()、accept()等。例如,可以通过ServerSocketChannel监听客户端的连接请求:

ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));while (true) {SocketChannel channel = serverChannel.accept();// 处理客户端的连接请求
}serverChannel.close();

二、Buffer(缓冲区)

Buffer用于存储数据,是Java NIO中的另一个核心组件。Buffer实际上是一个数组,可以通过Buffer来读写数据。Java NIO提供了多种类型的Buffer,常用的有ByteBuffer、CharBuffer、IntBuffer等。

Buffer有三个重要属性:容量(capacity)、位置(position)和限制(limit)。容量是Buffer的总大小,位置表示下一个要读或写的元素的索引,限制表示可以读或写的元素的数量。

Buffer的常用方法有put()、get()、flip()、clear()等。例如,可以通过Buffer读写数据:

ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("Hello".getBytes());
buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());
}buffer.clear();

三、Selector(选择器)

Selector是Java NIO中的另一个核心组件,用于高效地处理多个Channel。Selector会不断地轮询注册在其上的Channel,只有当至少一个Channel准备好进行读写操作时,Selector才会返回。

通过Selector,可以使用单个线程处理多个Channel,提高了系统的并发能力。Selector的常用方法有register()、select()等。例如,可以使用Selector处理多个Channel的读写操作:

Selector selector = Selector.open();
channel1.register(selector, SelectionKey.OP_READ);
channel2.register(selector, SelectionKey.OP_WRITE);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectedKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();if (key.isReadable()) {// 处理可读事件} else if (key.isWritable()) {// 处理可写事件}iterator.remove();}
}selector.close();

四、辅助类和接口

除了核心组件外,Java NIO还提供了其他一些辅助类和接口,如FileChannel(用于文件操作)、Charset(用于字符编码)、Pipe(用于两个线程间的单向管道通信)等。

FileChannel用于文件的读写操作,例如可以通过FileChannel读取文件的内容:

ByteBuffer buffer = ByteBuffer.allocate(1024);
FileChannel channel = new FileInputStream("file.txt").getChannel();while (channel.read(buffer) != -1) {buffer.flip();// 处理读取到的数据buffer.clear();
}channel.close();

Charset用于字符编码和解码,例如可以使用Charset将字符串转换成字节数组:

Charset charset = Charset.forName("UTF-8");
ByteBuffer buffer = charset.encode("Hello");while (buffer.hasRemaining()) {System.out.print((char) buffer.get());
}

Pipe用于两个线程间的单向管道通信,例如可以通过Pipe实现生产者-消费者模式:

Pipe pipe = Pipe.open();
Pipe.SinkChannel sinkChannel = pipe.sink();new Thread(() -> {String message = "Hello World!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());try {sinkChannel.write(buffer);} catch (IOException e) {e.printStackTrace();}
}).start();Pipe.SourceChannel sourceChannel = pipe.source();ByteBuffer buffer = ByteBuffer.allocate(1024);
sourceChannel.read(buffer);buffer.flip();
System.out.println(new String(buffer.array()));

五、Java NIO的优点

Java NIO相较于传统的Java I/O API具有以下优点:

  1. 更高的性能:Java NIO的非阻塞模式能够更好地处理大量的并发连接,提高了系统的吞吐量。

  2. 更少的线程开销:通过Selector,可以使用单个线程处理多个Channel,减少了线程的创建和上下文切换的开销。

  3. 更灵活的操作方式:Channel和Buffer的组合可以实现更灵活的读写操作,提供了更多的功能和选项。

案例

下面为你提供三个案例,展示如何使用Java NIO进行文件操作、网络通信和多路复用。

案例一:文件复制

public class FileCopyExample {public static void main(String[] args) throws IOException {FileChannel sourceChannel = new FileInputStream("source.txt").getChannel();FileChannel destinationChannel = new FileOutputStream("destination.txt").getChannel();ByteBuffer buffer = ByteBuffer.allocate(1024);while (sourceChannel.read(buffer) != -1) {buffer.flip();destinationChannel.write(buffer);buffer.clear();}sourceChannel.close();destinationChannel.close();}
}

该案例展示了如何使用FileChannel复制一个文件。首先,创建一个源文件通道sourceChannel和一个目标文件通道destinationChannel。然后,使用ByteBuffer读取源文件的数据,并写入目标文件中。

案例二:Socket通信

public class SocketCommunicationExample {public static void main(String[] args) throws IOException {SocketChannel channel = SocketChannel.open();channel.connect(new InetSocketAddress("localhost", 8080));String message = "Hello Server!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());channel.write(buffer);buffer.clear();channel.read(buffer);buffer.flip();String response = new String(buffer.array());System.out.println("Server response: " + response);channel.close();}
}

该案例展示了如何使用SocketChannel进行网络通信。首先,创建一个SocketChannel并连接到服务器。然后,将消息写入缓冲区,并通过SocketChannel发送给服务器。接着,从SocketChannel读取服务器的响应,并打印出来。

案例三:多路复用

public class SelectorExample {public static void main(String[] args) 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) {int readyChannels = selector.select();if (readyChannels == 0) {continue;}Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectedKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = client.read(buffer);if (bytesRead == -1) {client.close();continue;}buffer.flip();String message = new String(buffer.array());System.out.println("Received message: " + message);}iterator.remove();}}}
}

该案例展示了如何使用Selector进行多路复用。首先,创建一个Selector并打开一个ServerSocketChannel。然后,将ServerSocketChannel注册到Selector上,并指定感兴趣的事件为OP_ACCEPT。在循环中,通过调用selector.select()等待就绪的通道,并使用迭代器处理每个就绪的通道。如果是OP_ACCEPT事件,则接受客户端连接,并将SocketChannel注册到Selector上,感兴趣的事件为OP_READ。如果是OP_READ事件,则读取客户端发送的数据,并打印出来。

这些案例展示了Java NIO在文件操作、网络通信和多路复用方面的应用。通过使用Java NIO,可以提高系统的性能和可扩展性,更好地处理并发连接和I/O操作。

总结:

本文详细介绍了Java NIO的核心组件Channel、Buffer和Selector,以及其他一些辅助类和接口。通过使用Java NIO,可以实现高效的I/O操作,提高系统的并发能力。虽然Java NIO相对于传统的Java I/O API来说可能更加复杂,但一旦掌握了其使用方式,可以发挥出更大的潜力,提升系统的性能和可扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/94968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux下基本指令(上)

文章内容&#xff1a; 1. ls 指令 语法&#xff1a; ls [选项][目录或文件] 功能&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 单个ls显示当前目录下的文件和目录 常用选项&#…

flex布局与几个实例(含源码)

本文简单的说明下flex布局 有源码实例&#xff0c;后续会持续添加 flex默认主轴是横轴 容器主要有6个属性 flex-direction 决定主轴的方向 flex-direction: row | row-reverse | column | column-reverse; flex-wrap 决定是否换行 flex-wrap: nowrap | wrap | wrap-revers…

LLMs 用强化学习进行微调 RLHF: Fine-tuning with reinforcement learning

让我们把一切都整合在一起&#xff0c;看看您将如何在强化学习过程中使用奖励模型来更新LLM的权重&#xff0c;并生成与人对齐的模型。请记住&#xff0c;您希望从已经在您感兴趣的任务上表现良好的模型开始。您将努力使指导发现您的LLM对齐。首先&#xff0c;您将从提示数据集…

OpenGLES:3D立方体纹理贴图

效果展示 一.概述 前几篇博文讲解了OpenGLES绘制多种3D图形&#xff0c;并赋予丰富的色彩&#xff0c;但是在这些3D图形绘制过程中&#xff0c;有一点还没有涉及&#xff0c;就是纹理贴图。 今天这篇博文我会用如下六张图片对立方体进行纹理贴图&#xff0c;实现六个面都是贴…

Springboot中的@Import注解~

Import注解是Spring框架中的注解之一&#xff0c;用于导入其他配置类或者组件 Import注解的作用有以下几点&#xff1a; 导入其他配置类&#xff1a;可以使用Import注解导入其他的配置类&#xff0c;将其加入到当前配置类中&#xff0c;从而可以共享配置信息 导入其他组件&am…

开箱即用轻量级雪花算法id生成器Java工具类

开箱即用轻量级雪花算法id生成器Java工具类 1.1 背景1.2 雪花算法id生成器Java工具类 1.1 背景 在 Java后端研发过程中&#xff0c;对于分布式微服务来说&#xff0c;一般需要分布式 id生成. 这里分享一个非常好用且大多数情况下都可用的开箱即用轻量级雪花算法id生成器Java工…

英语——分享篇——每日100词——601-700

disastrous——adj.灾难性的&#xff0c;完全失败的——disast(e)r灾难(熟词)ous藕丝(拼音)——灾难性的地震后大家只能吃藕丝 disorder——n.骚乱&#xff0c;混乱&#xff1b;vt.使失调——dis的士(谐音)order命令(熟词)——的士司机命令我稳住那场骚乱 distract——vt.转移…

C++ - 布隆过滤器

前言 之前介绍了 位图&#xff0c;位图在判断某一个 数是否存在&#xff0c;或者在计算某个数是否出现 一次 或者 两次这些问题之上有着非常高效的实现复杂度&#xff0c;它的时间复杂度 可以达到 O&#xff08;1&#xff09;&#xff0c;因为都是逻辑判断和 &#xff0c;常数…

Web前端-Vue2+Vue3基础入门到实战项目-Day2(指令补充, computed计算属性, watch侦听器, 水果购物车)

Web前端-Vue2Vue3基础入门到实战项目-Day2 指令补充指令修饰符v-bind 对样式控制的增强控制class案例 - 京东秒杀tab导航高亮控制style案例 - 控制进度条 v-model 应用于其他表单元素 computed计算属性基本使用computed计算属性 vs methods方法计算属性完整写法案例 - 成绩 wat…

论文学习:RT-DETR

RT-DETR 摘要 DETR取得显著性能&#xff0c;但高成本计算使其无法发挥无NMS的优势&#xff0c;无法实际应用。本文分析了NMS对准确性和速度的负面影响&#xff0c;并建立端到端的速度基准。第一个实时端到端检测器&#xff0c;高效处理多尺度特征&#xff0c;并提出IoU-aware…

【云备份】

文章目录 [toc] 1 :peach:云备份的认识:peach:1.1 :apple:功能了解:apple:1.2 :apple:实现目标:apple:1.3 :apple:服务端程序负责功能:apple:1.4 :apple:服务端功能模块划分:apple:1.5 :apple:客户端程序负责功能:apple:1.6 :apple:客户端功能模块划分:apple: 2 :peach:环境搭建…

mac电脑任务管理器 Things3 for Mac中文

Things 3是一款效率软件&#xff0c;可以帮助用户规划一天行程、管理项目&#xff0c;并使使用者按部就班地朝目标迈进。以下是Things 3的主要特点和功能&#xff1a; 待办事项&#xff1a;以“待办事项”为基本组成部分&#xff0c;每一则待办事项都是迈向大成就的一小步。用…

scala入门

视频 scala学习配套视频 资料目录 网盘地址&#xff1a;https://pan.baidu.com/s/1vJzjHhaC1NCcAGry6SLIpg&pwd1706 文档资料下载 第一章Scala的相关概述 第二章变量 第三章运算符 第四章循环 第五章方法 第七章继承、抽象类、匿名类 第八章特质 第九章包、样例…

Redis-双写一致性

双写一致性 双写一致性解决方案延迟双删&#xff08;有脏数据的风险&#xff09;分布式锁&#xff08;强一致性&#xff0c;性能比较低&#xff09;异步通知&#xff08;保证数据的最终一致性&#xff0c;高并发情况下会出现短暂的不一致情况&#xff09; 双写一致性 当修改了数…

Docker镜像管理

Docker 基本管理 Docker 概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。 Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、…

Go 语言内置类型全解析:从布尔到字符串的全维度探究

目录 一、布尔类型定义基础用法声明与初始化逻辑运算 进阶用法条件语句循环结构函数返回值 常见错误与陷阱 二、整数类型定义基础用法声明与初始化运算符位运算 进阶用法数据溢出类型转换类型推断 特殊整数类型runebyte 常见问题和陷阱 三、浮点数类型定义基础用法声明与初始化…

云原生边缘计算KubeEdge安装配置

1. K8S集群部署&#xff0c;可以参考如下博客 请安装k8s集群&#xff0c;centos安装k8s集群 请安装k8s集群&#xff0c;ubuntu安装k8s集群 2.安装kubEedge 2.1 编辑kube-proxy使用ipvs代理 kubectl edit configmaps kube-proxy -n kube-system #修改kube-proxy#大约在40多行…

通过BeanFactotyPostProcessor动态修改@FeignClient的path

最近项目有个需求&#xff0c;要在启动后&#xff0c;动态修改FeignClient的请求路径&#xff0c;网上找到的基本都是在FeignClient里使用${…}&#xff0c;通过配置文件来定义Feign的接口路径&#xff0c;这并不能满足我们的需求 由于某些特殊原因&#xff0c;我们的每个接口…

Spring bean定义Spring Bean 的作用域

Spring bean定义 目录 Spring bean定义 Spring配置元数据 Spring Bean 的作用域 singleton作用域&#xff1a; 原型作用域&#xff1a; 示例&#xff1a; 形成应用程序的骨干是由Spring IoC容器所管理的对象称为bean。bean被实例化&#xff0c;组装&#xff0c;并通过Sprin…

运行pytorch时出现version `CXXABI_1.3.9‘ not found

发现问题&#xff1a;运行bert预测代码时出现如下错误 /envs/py38/lib/python3.8/site-packages/transformers/utils/import_utils.py", line 1184, in _get_module RuntimeError: Failed to import transformers.onnx.config because of the following error (look up …