从零开始学习Netty - 学习笔记 - NIO基础 - 文件编程:FileChannel,Path,Files

3.文件编程

3.1.FileChannel

FileChannel只能工作在非阻塞模式下面,不能和selector一起使用

获取

不能直接打开FIleChannel,必须通过FileInputSream,或者FileOutputSetream ,或者RandomAccessFile来获取FileChannel

  • 通过FileInputSream获取的channel只能
  • 通过FileOutputSetream 获取的channel只能
  • 通过RandomAccessFile 是否能读写,根据构造时指定的读写模式相关(“r”,“w”)
读取

会从channel读取数据填充到ByteBuffer中,返回的值,表示读到了多少字节,-1表示到达了文件的末尾

int read = channel.read(buffer);
写入

在while中调用 write方法,是因为 write方法并不能保证一次将buffer中的内容全部写入channel中

public void test4(){try (FileChannel channel = new RandomAccessFile("data.txt", "rw").getChannel()) {ByteBuffer b = ByteBuffer.allocate(10);b.put((byte) 'a');  // 存入数据b.put((byte) 'b');  // 存入数据b.put((byte) 'c');  // 存入数据b.flip(); // 切换为读模式// 在while中调用 write方法,是因为 write方法并不能保证一次将buffer中的内容全部写入channel中while (b.hasRemaining()){// 写入数据channel.write(b);}} catch (IOException e) {}
}

在这里插入图片描述

关闭

channel必须关闭,不过调用了FileInoutStreamFileOutputStream,或者RandomAccessFileclose方法会间接的调用channle的close方法

位置

channel.position 是 Java NIO 中用于获取通道(Channel)当前的位置的方法。通道的位置表示从数据源(如文件或网络连接)的开头到当前位置之间的字节数。

@Test
@DisplayName("测试channel.position()方法")
public void test5(){try (FileChannel channel = new RandomAccessFile("data.txt", "r").getChannel()) {// 获取当前通道的位置ByteBuffer buffer = ByteBuffer.allocate(10);buffer.put((byte) 'a');buffer.put((byte) 'a');buffer.put((byte) 'a');// 切换为读模式buffer.flip();channel.read(buffer);long position = channel.position();logger.error("Current position: {}", position);// 在文件中移动位置,假设移动到文件的开头channel.position(0);// 再次获取当前通道的位置position = channel.position();logger.error("Current position: {}", position);} catch (IOException e) {e.printStackTrace();}
}

在这里插入图片描述

  • channel.position() 返回当前通道的位置。
  • channel.position(0) 将通道的位置移动到文件的开头。
  • 通过调用 position() 方法,你可以控制从文件的哪个位置读取数据,或者从哪个位置开始写入
大小

使用size可以获取文件的大小

long size = channel.size();
强制写入

强制写入操作可以看作是将缓冲区中的数据内容直接写入到磁盘上,而不依赖于操作系统的延迟写入策略(因为出于性能考虑,操作系统会将数据进行缓存,而不是立刻写入磁盘)。这样可以保证写入数据的即时性和持久性,但同时也会增加写入操作的开销和系统的负载。

// 假设 channel 是一个 FileChannel 对象
channel.force(true); // 执行强制写入操作

3.2.两个Channel之间传递数据

transferTo() 方法是 Java NIO 中的一个用于通道之间数据传输的方法。这个方法允许将数据从一个通道直接传输到另一个通道,而不需要中间缓冲区。

在Java NIO中,数据可以在通道之间直接传输,而不必经过缓冲区。这种直接传输的方式在大数据量传输时能够提高性能并降低内存消耗。

transferTo() 方法通常用于将一个通道的数据传输到另一个通道,例如将一个文件通道的内容传输到网络套接字通道,或者将一个输入流传输到输出流。

零拷贝transferTo()底层就是使用了零拷贝进行优化

  1. 当调用 transferTo() 方法时,底层操作系统会尝试将数据直接从源通道传输到目标通道,而不需要经过用户空间的缓冲区。
  2. 操作系统会使用DMA(直接内存访问)技术,从源文件的内核缓冲区中直接读取数据,并将数据直接写入目标文件的内核缓冲区中。
  3. 这样,数据不需要经过用户空间的缓冲区,也不需要额外的数据复制操作,从而实现了零拷贝的数据传输
	@Test@DisplayName("两个Channel之间传递数据")public void test6(){try(FileChannel FROM = new FileInputStream("data.txt").getChannel();FileChannel TO = new FileOutputStream("data2.txt").getChannel();) {// 1.从FROM中读取数据 TO中写入数据 但是最大只能传输2G// 2.left变量表示还剩余多少字节没有传输long size = FROM.size();for (long left = size; left > 0;){// 每次传输的字节大小 会返回long l = FROM.transferTo((size-left), left, TO);// 3.每次传输完毕后,更新left的值left -= l;}} catch (IOException e) {e.printStackTrace();}}

3.3.Path

JDK 7 以后引入 Path 和 Paths两个类

  • **Path:**用来表示文件的路径

    • 创建路径

      • Paths.get(String first, String... more):创建路径实例。
      • Path resolve(String other):解析相对路径。
    • 获取路径信息

      • Path getFileName():获取路径中的文件名部分。
      • Path getParent():获取路径中的父路径部分。
      • int getNameCount():获取路径的名称元素数量。
      • Path getName(int index):获取路径中指定索引位置的名称元素。
    • 判断路径属性

      • boolean isAbsolute():判断路径是否为绝对路径。
      • boolean startsWith(String other) / boolean endsWith(String other):判断路径是否以指定字符串开始或结束。
    • 转换路径

      • Path toAbsolutePath():将路径转换为绝对路径。
      • Path relativize(Path other):获取当前路径相对于另一路径的相对路径。
    • 比较路径

      • int compareTo(Path other):比较两个路径的字典顺序。
    • 判断文件系统操作

      • boolean exists():判断路径所代表的文件或目录是否存在。
      • boolean isRegularFile() / boolean isDirectory():判断路径表示的是否为普通文件或目录。
      • boolean isReadable() / boolean isWritable() / boolean isExecutable():判断文件是否可读、可写、可执行。
    • 操作路径

      • Path normalize():规范化路径,解析 ... 等符号。
      • Path resolveSibling(Path other):返回当前路径的父路径与给定路径的相对路径组合而成的路径。
      • void createDirectory():创建一个目录。
      • void createFile():创建一个文件。
    • 遍历目录

      • DirectoryStream<Path> newDirectoryStream(Path dir):返回目录中的条目的目录流。
    • 读取文件内容

      • byte[] readAllBytes():读取文件的所有字节并返回一个字节数组。
      • List<String> readAllLines():读取文件的所有行并返回一个字符串列表。
    • 删除文件或目录

    • boolean deleteIfExists():删除指定的文件或目录。

  • **Paths:**是工具类,用来获取Path的实例

// 相对路径,根据user.dir 环江变量来定位 data.txt
Path path = Paths.get("data.txt");
logger.error("path: {}", path.toAbsolutePath());// 绝对路径
Paths.get("D:\\dcjet\\java_base_study\\data.txt");
logger.error("path: {}", path.toAbsolutePath());// 绝对路径
Paths.get("D:/dcjet/java_base_study/data.txt");
logger.error("path: {}", path.toAbsolutePath());// 绝对路径
Paths.get("D:\\dcjet\\java_base_study\\", "data.txt");
logger.error("path: {}", path.toAbsolutePath());

在这里插入图片描述

... 是用于表示目录结构中的当前目录和父目录的特殊符号。

  • .:表示当前目录,即当前所在位置的目录。
  • ..:表示父目录,即当前目录的上一级目录。
root/├── documents/│   ├── file1.txt├── pictures/└── videos/

documents 目录中,. 表示 documents 目录本身,.. 表示 root 目录

3.4.Files

  1. 复制文件或目录

    Path source = Paths.get("source.txt");
    Path target = Paths.get("target.txt");
    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    
  2. 移动文件或目录

    Path source = Paths.get("source.txt");
    Path target = Paths.get("target.txt");
    Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
    
  3. 删除文件或目录

    Path path = Paths.get("file.txt");
    // 如果目录还有文件 会有报错
    // 如果删除的目录 不存在 也会报错
    Files.delete(path);
    
  4. 创建文件或目录

    // 可以创建多级目录
    Path dir = Paths.get("test/d1/d2");
    // 只能创建一级目录
    Files.createDirectory(dir);
    // 创建多级目录
    Files.createDirectories(dir);
    
  5. 读取文件内容

    Path path = Paths.get("file.txt");
    byte[] bytes = Files.readAllBytes(path);
    
  6. 写入文件内容

    Path path = Paths.get("file.txt");
    List<String> lines = Arrays.asList("Hello", "World");
    Files.write(path, lines, StandardCharsets.UTF_8);
    
  7. 判断文件或目录属性

    Path path = Paths.get("file.txt");
    boolean exists = Files.exists(path);
    boolean isRegularFile = Files.isRegularFile(path);
    
  8. 比较文件内容

    Path path1 = Paths.get("file1.txt");
    Path path2 = Paths.get("file2.txt");
    boolean isSameFile = Files.isSameFile(path1, path2);
    
  9. 获取文件或目录属性

    Path path = Paths.get("file.txt");
    FileStore fileStore = Files.getFileStore(path);
    
  10. 遍历目录

    Path dir = Paths.get("directory");
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {for (Path entry : stream) {System.out.println(entry.getFileName());}
    } catch (IOException e) {e.printStackTrace();
    }
    
  11. 其他操作

    遍历文件夹

    @Test
    @DisplayName("遍历文件夹")
    public void test8() {Path path = Paths.get("D:\\dcjet\\java_base_study\\src\\main\\java\\com\\hrfan\\java_se_base\\netty\\nio");try {// 遍历文件夹(访问者模式应用)Files.walkFileTree(path, new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {// 遍历之前logger.error("file: {}", file);return FileVisitResult.CONTINUE;}});} catch (IOException e) {e.printStackTrace();}
    }
    
    • 在这里插入图片描述

      删除多级目录

      在这个案例中使用 Files.walkFileTree() 方法遍历了目录树,并在 visitFile() 方法中删除了每个文件,在 postVisitDirectory() 方法中删除了每个目录。注意,删除操作会递归删除目录中的所有文件和子目录。

      @Test
      @DisplayName("删除目录")
      public void test9() {AtomicInteger atomicInteger = new AtomicInteger(0);Path path = Paths.get("D:\\aa\\adsa");try {// 遍历文件夹Files.walkFileTree(path, new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.delete(file); // 删除文件logger.error("delete file: {}", file);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {// 删除目录(退出时删除目录因为此时目录中没有文件了)Files.delete(dir);logger.error("delete dir: {}", dir);return super.postVisitDirectory(dir, exc);}});// 最终遍历完成logger.error("get file number: {}", atomicInteger.get());} catch (IOException e) {e.printStackTrace();}
      }
      

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

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

相关文章

互联网高科技公司领导AI工业化,MatrixGo加速人工智能落地

作者&#xff1a;吴宁川 AI&#xff08;人工智能&#xff09;工业化与AI工程化正在引领人工智能的大趋势。AI工程化主要从企业CIO角度&#xff0c;着眼于在企业生产环境中规模化落地AI应用的工程化举措&#xff1b;而AI工业化则从AI供应商的角度&#xff0c;着眼于以规模化方式…

Rust ?运算符 Rust读写txt文件

一、Rust &#xff1f;运算符 &#xff1f;运算符&#xff1a;传播错误的一种快捷方式。 如果Result是Ok&#xff1a;Ok中的值就是表达式的结果&#xff0c;然后继续执行程序。 如果Result是Err&#xff1a;Err就是整个函数的返回值&#xff0c;就像使用了return &#xff…

电脑wifi丢失修复

当你打开电脑突然发现wifi功能不见了&#xff0c;可以先查看一下网卡的状态 在控制面板中找到设备管理器&#xff0c;打开就能找到网络适配器&#xff0c; 我这里是修复过的&#xff0c;wifi丢失后这里可能会显示WALN是丢失的&#xff0c;其他项显示黄色感叹号。 如何修复呢…

Go语言中的TLS加密:深入crypto/tls库的实战指南

Go语言中的TLS加密&#xff1a;深入crypto/tls库的实战指南 引言crypto/tls库的核心组件TLS配置&#xff1a;tls.Config证书加载与管理TLS握手过程及其实现 构建安全的服务端创建TLS加密的HTTP服务器配置TLS属性常见的安全设置和最佳实践 开发TLS客户端应用编写使用TLS的客户端…

[游戏开发][虚幻5]新建项目注意事项

鼠标右键点击Client.uproject文件&#xff0c;可以看到三个比较关键的选项&#xff0c; 启动游戏&#xff0c;生成sln解决方案&#xff0c;切换引擎版本 断点调试 C代码重要步骤 如果你想断点调试C代码&#xff0c;则必须使用使用代码编译启动引擎&#xff0c;你需要做几个操作…

Backend - Docker 离线卸载

目录 一、卸载 docker 1. 停止 docker 2. 删除相关文件 3. 重新加载配置文件 4. 移除 docker 二、卸载 docker-compose 三、查看 Docker-compose 和 Docker、docker.service 是否卸载干净 1. 首先确定自己安装的目录 2. 进入这三个目录下查看文件夹 3. 删除docker-se…

Python 正斜杠 (斜杠 /) 和反斜杠 (倒斜杠 \)

Python 正斜杠 [斜杠 /] 和反斜杠 [倒斜杠 \] 1. Windows2. LinuxReferences 1. Windows 倒斜杠有两个&#xff0c;因为每个倒斜杠需要由另一个倒斜杠字符来转义。 Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\fore…

从零开始学习Netty - 学习笔记 - NIO基础 - 网络编程: Selector

4.网络编程 4.1.非阻塞 VS 阻塞 在网络编程中&#xff0c;**阻塞&#xff08;Blocking&#xff09;和非阻塞&#xff08;Non-blocking&#xff09;**是两种不同的编程模型&#xff0c;描述了程序在进行网络通信时的行为方式。 阻塞&#xff08;Blocking&#xff09;&#xff1…

C#中使用list封装多个同类型对象以及组合拓展实体的应用

文章目录 一、list使用方法二、C#组合拓展实体 一、list使用方法 在C#中&#xff0c;使用List<T>集合是封装多个同类型对象的常用方式。List<T>是泛型集合&#xff0c;T是集合中元素的类型。下面是一个简单的例子&#xff0c;演示如何创建一个List<T>&#…

鸿蒙 gnss 开关使能流程

先WiFi&#xff0c;后 定位&#xff0c;再从蓝牙到NFC&#xff0c;这个就是我大致熟悉开源鸿蒙代码的一个顺序流程&#xff0c;WiFi 的年前差不多基本流程熟悉了&#xff0c;当然还有很多细节和内容没有写到&#xff0c;后续都会慢慢的丰富起来&#xff0c;这一篇将开启GNSS的篇…

js设计模式:计算属性模式

作用: 将对象中的某些值与其他值进行关联,根据其他值来计算该值的结果 vue中的计算属性就是很经典的例子 示例: let nowDate 2023const wjtInfo {brithDate:1995,get age(){return nowDate-this.brithDate}}console.log(wjtInfo.age,wjt年龄)nowDate 1console.log(wjtInf…

mq大量消息堆积有哪些解决方案

当消息队列中出现大量消息堆积时&#xff0c;可能会导致系统性能下降、消息延迟增加以及服务不可用等问题。针对这种情况&#xff0c;可以采取以下几种解决方案&#xff1a; 增加消费者数量&#xff1a;增加消费者数量可以提高消息消费的速度&#xff0c;缩短消息队列中消息的处…

在 Windows 上安装 Redis 过程全记录(使用WSL在Windows中搭建虚拟环境)

在Windows上使用Redis进行开发 Windows 上不正式支持 Redis。但是&#xff0c;您可以按照以下说明在 Windows 上安装 Redis 进行开发&#xff0c;本教程采用WSL方式安装Linux虚拟环境&#xff08;并非唯一方式&#xff0c;也可通过其他方式安装Linux虚拟环境&#xff0c;本教程…

flink分区与算子链

flink分区与算子链 flink 分区策略flink 什么情况下才会把 Operator chain 在一起形成算子链&#xff1f; flink 分区策略 GlobalPartitioner 数据会被分发到下游算子的第一个实例中进行处理RebalancePartitioner 数 据会 被循 环发 送到 下 游的 每一 个实 例中 进 行处 理。…

【算法与数据结构】1020、130、LeetCode飞地的数量 被围绕的区域

文章目录 一、1020、飞地的数量二、130、被围绕的区域三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、1020、飞地的数量 思路分析&#xff1a;博主认为题目很抽象&#xff0c;非常难理解。想了好久&#xff0c;要理解…

【蝶变跃升】壹起来|就业辅导系列活动——职业生涯规划和模拟面试

为使困难家庭更深层次了解自己就业现状&#xff0c;明确就业方向&#xff0c;同时提升在面试时的各类技巧。2024年2月17日&#xff0c;由平湖市民政局主办、平湖吾悦广场和上海聘也科技有限公司协办、平湖市壹起来公益发展中心承办的“蝶变跃升”就业辅导系列——职业生涯规划和…

2024新版Java高频面试题+Java八股文面试真题

Java面试题_2024新版Java高频面试题Java八股文面试真题 Java高频面试专题视频课程&#xff0c;瓤括了Java生态下的主流技术面试题&#xff0c;课程特色&#xff1a; 1、全面&#xff0c;jvm、并发编程、mysql、rabbitmq、spring、mybatis、redis、分布式、微服务、数据结构等等…

零基础到高级:Android音视频开发技能路径规划

音视频开发趋势 Android音视频开发领域目前正处于一个高速发展的阶段&#xff0c;主要趋势如下&#xff1a; 超高清视频&#xff1a;4K视频亚毫米级显示清晰&#xff0c;更加逼真&#xff0c;为开发更加逼真的虚拟现实应用提供了基础。AI技术&#xff1a;自适应码率控制、视频…

GIT使用和简介

Git 是一个版本控制系统&#xff0c;它可以追踪文件的更改&#xff0c;并可以在不同的分支上进行并行开发。下面是 Git 的基本概念和使用方式的解释&#xff1a; 1. 仓库&#xff08;Repository&#xff09;&#xff1a;仓库是用来存储项目代码的地方。一个仓库可以包含多个文…

Flutter学习4 - Dart数据类型

1、基本数据类型 num、int、double &#xff08;1&#xff09;常用数据类型 num类型&#xff0c;是数字类型的父类型&#xff0c;有两个子类 int 和 double 通过在函数名前加下划线&#xff0c;可以将函数变成私有函数&#xff0c;私有函数只能在当前文件中调用 //常用数据…