深入学习和理解Java NIO的高级特性

学习使用Path、Paths和Files类来操作文件系统

在Java 7引入的NIO.2(New Input/Output 2)中,PathPathsFiles类是处理文件系统操作的核心类。它们提供了一套强大的文件I/O操作接口,使得读写文件、访问文件属性、遍历文件目录等操作变得更加简洁和直观。

Path和Paths

Path接口代表文件系统中的路径。它不仅可以用来表示文件,也可以表示目录。Path对象包含了文件系统的层级结构,并提供了许多用于路径操作的方法,如解析、比较、绝对路径获取等。

Paths是一个工具类,提供了静态方法来更容易地获取Path对象。

创建Path对象

使用Paths.get(String first, String... more)方法可以创建Path对象:

Path path = Paths.get("/home/user/docs/myfile.txt");
Path anotherPath = Paths.get("home", "user", "docs", "myfile.txt");

Files类

Files类提供了静态方法来操作文件和目录,如创建、删除、复制、移动文件/目录,读取文件内容,写入文件内容,以及访问文件的属性等。

文件操作
  • 读取文件内容
Path path = Paths.get("data.txt");
List<String> lines = Files.readAllLines(path);

写入文件内容

Path path = Paths.get("output.txt");
List<String> lines = Arrays.asList("Line 1", "Line 2");
Files.write(path, lines, StandardCharsets.UTF_8);
文件和目录的创建与删除
  • 创建文件
Path newPath = Files.createFile(Paths.get("newFile.txt"));

创建目录

Path newDir = Files.createDirectories(Paths.get("newDir/subDir"));

删除文件/目录

Files.delete(Paths.get("toBeDeleted.txt"));
文件复制和移动
  • 复制文件
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);

移动文件

Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
访问文件属性

Files类提供了方法来检查和修改文件的属性,比如大小、最后修改时间、权限等。

Path path = Paths.get("example.txt");
long size = Files.size(path);
FileTime fileTime = Files.getLastModifiedTime(path);
遍历目录

使用Files.walk(Path start, int maxDepth, FileVisitOption... options)方法可以遍历目录:

try (Stream<Path> stream = Files.walk(Paths.get("startDir"), 3)) {stream.forEach(System.out::println);
}

总结

PathPathsFiles类极大地简化了文件系统的操作,提供了一种更现代、更直观的API来处理文件和目录。通过这些类,开发者可以轻松执行文件读写、属性访问、目录遍历等操作,而不必处理传统java.io包中繁琐的文件处理方式。熟练使用这些NIO.2中的类对于进行高效、可靠的文件操作至关重要。

AsynchronousFileChannel实现异步文件I/O操作

AsynchronousFileChannel是Java NIO.2中引入的一个功能强大的类,它支持对文件的异步读写操作。这意味着程序可以启动一个读写文件的操作,在等待操作完成的同时,还能继续执行其他任务。当文件I/O操作实际完成时,程序将通过回调或Future对象获得通知。这种机制特别适合于处理大文件或执行密集的I/O操作,能显著提高应用程序的响应性和性能。

使用AsynchronousFileChannel

打开AsynchronousFileChannel

要使用AsynchronousFileChannel,首先需要打开一个文件通道。可以通过调用open()方法实现,这个方法需要一个Path对象和一组OpenOption参数来指定如何打开文件。

Path path = Paths.get("example.txt");
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE);
异步读取文件

异步读取文件可以通过read()方法实现,这个方法接受一个ByteBuffer作为容器来存储读取的数据,一个文件位置指示从哪里开始读取,以及一个附件对象和一个CompletionHandler作为回调来处理操作完成或失败的情况。

ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;fileChannel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {System.out.println("Read done, result = " + result);}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {System.err.println("Read failed");exc.printStackTrace();}
});
异步写入文件

异步写入文件与读取类似,使用write()方法。这个方法同样需要一个ByteBuffer来提供写入的数据,一个文件位置,以及一个附件对象和一个CompletionHandler

String input = "Hello, Asynchronous World!";
ByteBuffer buffer = ByteBuffer.wrap(input.getBytes());
long position = 0;fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {System.out.println("Write done, result = " + result);}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {System.err.println("Write failed");exc.printStackTrace();}
});
使用Future处理结果

除了使用CompletionHandlerAsynchronousFileChannel的读写操作也可以返回一个Future对象,你可以用它来查询操作的状态或等待操作完成。

ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> future = fileChannel.read(buffer, 0);// 使用Future等待异步操作完成
Integer result = future.get();
System.out.println("Read done, result = " + result);

总结

AsynchronousFileChannel提供了一种高效的机制来执行非阻塞的文件I/O操作,使得应用程序在进行大量I/O操作时仍能保持高响应性。通过异步操作的回调机制(CompletionHandler)或Future对象,开发者可以灵活地控制程序的流程,优化应用性能。掌握AsynchronousFileChannel对于开发高性能的Java应用至关重要。

练习使用选择器(Selectors)和套接字通道(Socket Channels)进行网络编程

使用选择器(Selectors)和套接字通道(Socket Channels)是Java NIO中处理网络操作的核心机制。它们允许单个线程同时管理多个网络连接,这是通过非阻塞I/O(NIO)实现的。这种模型相比于传统的每个连接使用一个线程的方式(如Java IO中的ServerSocketSocket),可以大幅度提高网络应用的可伸缩性和性能。

步骤1: 创建选择器

选择器是Java NIO中的一个组件,用于检测一个或多个NIO通道(Channel)的状态变化(例如,连接打开、数据到达)。首先,你需要创建一个选择器实例:

Selector selector = Selector.open();

步骤2: 创建套接字通道

接下来,创建一个非阻塞的套接字通道(Socket Channel)。对于服务器端,你需要创建一个ServerSocketChannel并绑定到特定端口。对于客户端,创建一个SocketChannel并连接到服务器。

服务器端:
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false); // 配置为非阻塞模式
serverChannel.bind(new InetSocketAddress("localhost", 8080));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
客户端:
SocketChannel clientChannel = SocketChannel.open();
clientChannel.configureBlocking(false);
clientChannel.connect(new InetSocketAddress("localhost", 8080));
clientChannel.register(selector, SelectionKey.OP_CONNECT);

步骤3: 选择器循环

一旦选择器和通道设置完毕,你就可以使用选择器循环来等待事件的发生(如新连接的接受、数据的读取或写入)。

while(true) {selector.select(); // 阻塞,直到至少有一个注册的事件发生Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while(keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if(key.isAcceptable()) {// 处理接受新连接ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel client = serverChannel.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);System.out.println("Accepted new connection from client: " + client);} else if(key.isReadable()) {// 处理读SocketChannel client = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int numRead = client.read(buffer);if(numRead > 0) {// 处理数据System.out.println("Read data: " + new String(buffer.array()));} else if(numRead == -1) {// 连接已经关闭client.close();}}// 移除已选的键,因为已经处理过了keyIterator.remove();}
}

步骤4: 数据读取和写入

在选择器循环中,当你检测到OP_READ事件时,可以从通道中读取数据。同样,当你要写入数据到通道时,可以注册OP_WRITE事件,但在写入数据前通常不需要注册写事件,只有在写缓冲区满时才注册OP_WRITE事件,完成写操作后取消注册。

// 写数据示例
String message = "Hello from server!";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
clientChannel.write(buffer);

总结

通过上述步骤,你可以使用选择器和套接字通道在Java中实现高效的网络编程。这种方法相比于传统的阻塞IO模型,可以处理成千上万的并发连接,是构建高性能网络应用的关键技术之一。实践这些概念将帮助你更好地理解非阻塞IO的工作机制,并在实际项目中运用它们。

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

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

相关文章

解锁基于LLMS的咒语:通过上下文学习重新思考对齐

一、写作动机&#xff1a; 最近的一项研究&#xff0c;LIMA&#xff0c;表明仅使用1K个示例进行SFT也可以实现显著的对齐性能&#xff0c;这表明对齐微调的效果可能是“表面的”。&#xff08;知识和推理能力来源于预训练&#xff0c;而不是必须通过对齐微调获得的。&#xff…

计算机图形学学习(一)——线的绘制、三角形填充绘制

以下摘抄自本人的计算机图形学上机报告 实验内容及要求&#xff1a; 理解并掌握中点画线法、Bresenham算法、扫描线法和重心坐标法的基本原理和算法步骤。使用编程语言C实现上述算法&#xff0c;并编写相应的代码。对于直线绘制算法&#xff0c;要求能够绘制水平、垂直、斜向等…

Python助力:高效合并多个Word文档

目录 写在开头1 准备工作1.1 安装Python环境1.2 安装必要的库 2 理解Word文档的结构2.1 python-docx库的基本使用2.2 文档基本组成2.2.1 段落2.2.2 表格2.2.3 图片2.2.4 页眉和页脚 3 编写合并Word文档的脚本3.1 创建新的Word文档3.2 读取并合并文档内容3.2.1 合并段落3.2.2 合…

【消息队列开发】 实现内存加载

文章目录 &#x1f343;前言&#x1f333;实现思路&#x1f6a9;读取消息长度&#x1f6a9;读取相应长度的消息&#x1f6a9;进行反序列化&#x1f6a9;判定是否有效&#x1f6a9;加入有效消息&#x1f6a9;收尾工作&#x1f6a9;代码实现 ⭕总结 &#x1f343;前言 本次开发目…

未解决的问题:字符数组中元素的个数

情形1&#xff1a; #include<stdio.h> int main() {int arr_int1[10];int arr_int2[]{1,2,3,4,5};char arr_char1[10];char arr_char2[]"world";char arr_char3[]{h,e,l,l,o};int i;i0;while(arr_char2[i]!\0){i;}printf("%d\n",i);i0;while(arr_ch…

mediapipe最小编译、插件开发及demo

mediapipe最小编译、插件开发及demo 1.创建容器2.修改apt源3.安装依赖4.安装conda环境5.安装cmake6.安装bazel7.安装Opencv(非必须)8.下载 mediapipe 0.8.119.编译最简版本的mediapipe10.拷贝编译好的库和头文件11.sample插件的参数12.插件源码13.编译插件14.demo源码15.编译de…

C语言顺序、选择、循环结构与预处理

C语言程序设计&#xff0c;知识一遍过 &#x1f525;温馨提示&#x1f525;&#xff1a;使用电脑端阅读&#xff0c;获取更好体验&#x1f680; 【参考】C 语言教程 | 菜鸟教程 (runoob.com) 文章目录 C语言程序设计&#xff0c;知识一遍过顺序结构表达式语句字符的输入与输出格…

lwip优化任务优先级

在lwIP中&#xff0c;ethernetif_input线程负责接收和处理从以太网接口接收到的数据包&#xff0c;而tcpip主线程则负责处理lwIP协议栈中的各种事件和数据包。一般情况下&#xff0c;ethernetif_input线程的优先级应该设置为低于tcpip主线程的优先级。 这是因为在实时操作系统…

HarmonyOS ArkUI入门—HarmonyOS ArkUI来开发一个健康饮食应用

本文演示如果在DevEco Studio 3里面&#xff0c;用HarmonyOS的ArkUI来开发一个健康饮食应用。体验HarmonyOS 3最新API 9&#xff01; 获取HarmonyOS应用 HarmonyOS的ArkUI来开发一个健康饮食的ArkUI程序“ArkUIHealthyDiet”&#xff0c;基础代码已经有了[1]&#xff0c;个人…

20 OpenCV像素重映

文章目录 像素重映remap 重映算子代码示例 像素重映 简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去&#xff0c;形成一张新的图像。 g(x,y)是重映射之后的图像&#xff0c;h(x,y)是功能函数&#xff0c;f是源图像 remap 重映算子 Remap…

Java项目:52 springboot基于SpringBoot的旅游网站的设计与实现013

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 旅游网站主要功能如下&#xff1a; 1.用户管理&#xff1a;注册、登录、退出、修改密码&#xff1b; 2.分类显示&#xff1a;显示旅游路线的分类&am…

MD5算法:密码学中的传奇

title: MD5算法&#xff1a;密码学中的传奇 date: 2024/3/15 20:08:07 updated: 2024/3/15 20:08:07 tags: MD5起源算法原理安全分析优缺点比较技术改进示例代码应用趋势 MD5算法起源&#xff1a; MD5&#xff08;Message Digest Algorithm 5&#xff09;算法是由MIT的计算机…

OpenHarmony教程指南—ArkTS时钟

简单时钟 介绍 本示例通过使用ohos.display 接口以及Canvas组件来实现一个简单的时钟应用。 效果预览 使用说明 1.界面通过setInterval实现周期性实时刷新时间&#xff0c;使用Canvas绘制时钟&#xff0c;指针旋转角度通过计算得出。 例如&#xff1a;"2 * Math.PI /…

Python QT 之PySide6简单入门

目录 1.开发环境配置 1.1 下载PySide6 2.2 配置pycharm相关快捷方式 PySide6_Designer - QT Designer 设计UI PySide6_UIC - 将QT Designer生成的UI文件转换为python文件 PySide6_RCC - 将RCC文件转换为python文件 2.第一个开发实例 2.1 QT desiger设计界面 2.2 将ui文…

21.AUTOSAR MCAL分析(二):Memory Driver

目录 1. AUTOSAR Memory Driver模块概述 2. Flash Driver 3. EEPROM Driver 4. Flash Test 5. RAM Test 6.小结

一篇普通的生活周记

学习进度汇报&#xff1a; 这周主要是参考着视频敲完了一个vue2后台项目&#xff0c;主要是vue2element-ui,因为之前写项目的时候用过lay-ui&#xff0c;虽然是结合着node.js写的&#xff0c;但是大差不差&#xff0c;所以上手也很快。同时&#xff0c;学长发给我们了ruoyi项目…

关于如何重燃学习的激情

3月1日是我回学校的第一天。经历了长达8个月在家的昏暗时刻&#xff0c;我这10天的感觉和在家的感觉发生了翻天覆地的变化&#xff0c;最明显的莫过于学习状态的改变。 倒不是说在家学的不好&#xff0c;而是说在学校&#xff0c;我对学习的整体感觉&#xff0c;以及专注程度&…

【Leetcode每日一题】 递归 - 反转链表(难度⭐)(35)

1. 题目解析 题目链接&#xff1a;206. 反转链表 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 一、递归函数的核心任务 递归函数的主要职责是接受一个链表的头指针&#xff0c;并返回该链表逆序后的新头结点。递归…

【LeetCode热题100】160. 相交链表(链表)

一.题目要求 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数…

C++超详细知识点(五):类的友元函数和友元类

目录 标题&#xff1a; 友元函数和友元类1. 友元函数2. 友元类 标题&#xff1a; 友元函数和友元类 友元函数和友元类是C中的概念&#xff0c;它们允许某些函数或类访问另一个类的私有成员。这样的访问权限超过了通常的私有和保护访问级别。请注意&#xff0c;友元类的使用应该…