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

news/发布时间2024/5/15 15:46:19

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.bcls.cn/SGnj/2365.shtml

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

相关文章

如何使用Docker本地部署Jupyter+Notebook容器并结合内网穿透实现远程访问

文章目录 1. 选择与拉取镜像2. 创建容器3. 访问Jupyter工作台4. 远程访问Jupyter工作台4.1 内网穿透工具安装4.2 创建远程连接公网地址4.3 使用固定二级子域名地址远程访问 本文主要介绍如何在Ubuntu系统中使用Docker本地部署Jupyter Notebook&#xff0c;并结合cpolar内网穿透…

《Go 简易速速上手小册》第10章:微服务与云原生应用(2024 最新版)

文章目录 10.1 构建微服务架构 - 探索 Go 语言的微观世界10.1.1 基础知识讲解10.1.2 重点案例:订单处理系统订单服务测试服务10.1.3 拓展案例 1:用户认证服务安装所需的包实现用户模型和存储实现 JWT 生成和验证实现认证服务测试服务10.1.4 拓展案例 2:商品推荐服务设计商品…

深入浅出熟悉OpenAI最新大作Sora文生视频大模型

蠢蠢欲动&#xff0c;惴惴不安&#xff0c;朋友们我又来了&#xff0c;这个春节真的过的是像过山车&#xff0c;Gemini1.5 PRO还没过劲&#xff0c;OpenAI又放大招&#xff0c;人类真的要认输了吗&#xff0c;让我忍不住想要再探究竟&#xff0c;到底是什么让文生视频发生了质的…

Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)

5、查看证书是否安装成功 方式一&#xff1a; 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项&#xff1a;Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器&#xff0c;选择操作—>查看证书&#xff0c;在搜索…

建造者模式

1.模式定义: 将一个复杂对象的创建与他的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示 2.应用场景 1.需要生成的对象具有复杂的内部结构 2.需要生成的对象内部属性本身相互依赖 3.与不可变对象配合使用 3.优点&#xff1a; 1、建造者独立&#xff0c;易扩展…

Django视图

HttpRequests对象 利用http协议向服务器传参的4种途径 提取url特定部分&#xff0c;如/web/index/&#xff0c;可以通过在服务器端的路由中用正则表达式截取查询字符串&#xff0c;形如?key1value&keyvalue2&#xff0c;&#xff08;&#xff1f;前面是路由&#xff0c;…

C++ 调用js 脚本

需求&#xff1a; 使用Qt/C 调用js 脚本。Qt 调用lua 脚本性能应该是最快的&#xff0c;但是需要引入第三方库&#xff0c;虽然也不是特别麻烦&#xff0c;但是调用js脚本&#xff0c;确实内置的功能&#xff08;C 调用lua 脚本-CSDN博客&#xff09; 步骤&#xff1a; 1&…

鸿蒙会成为安卓的终结者吗?

随着近期鸿蒙OS系统推送测试版的时间确定&#xff0c;关于鸿蒙系统的讨论再次升温。 作为华为自主研发的操作系统&#xff0c;鸿蒙给人的第一印象是具有颠覆性。 早在几年前&#xff0c;业内就开始流传鸿蒙可能会代替Android的传言。毕竟&#xff0c;Android作为开源系统&…

蓝桥杯嵌入式第9届真题(完成) STM32G431

蓝桥杯嵌入式第9届真题(完成) STM32G431 题目 分析和代码 main.h /* USER CODE BEGIN Header */ /********************************************************************************* file : main.h* brief : Header for main.c file.* …

[论文精读]Do Transformers Really Perform Bad for Graph Representation?

论文网址&#xff1a;[2106.05234] Do Transformers Really Perform Bad for Graph Representation? (arxiv.org) 论文代码&#xff1a;https://github.com/Microsoft/Graphormer 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼…

几个常见的C/C++语言冷知识

当涉及到C/C语言时&#xff0c;有一些冷知识可能并不为人所熟知&#xff0c;但却可以让你更深入地理解这门古老而强大的编程语言。以下是一些有趣的C/C语言冷知识。 1. 数组的下标可以是负数 在我们日常的C语言编程中&#xff0c;数组是一个非常常见的数据结构。我们习惯性地使…

【C语言】深度探讨文件操作(一)

文章目录 &#x1f4dd;前言&#x1f320; 为什么使用文件&#xff1f;&#x1f309;什么是文件&#xff1f; &#x1f320;程序文件&#x1f309;数据文件 &#x1f320;文件名&#x1f309;二进制文件和文本文件&#xff1f; &#x1f320;文件的打开和关闭&#x1f309; 流和…

FPS游戏漫谈弱网环境时延优化

游戏在弱网情况下会变得体验很差&#xff0c;玩家的直观感受就是我的操作怎么没有反应&#xff0c;整个游戏世界都是一卡一顿的。这个就是因为网络问题导致了游戏体验变差。 那什么是弱网环境&#xff1f;弱网环境就是指网络不好的环境&#xff0c;尤其是移动网络下&#xff0…

edge安装fdm插件

下载 https://www.crxsoso.com/webstore/detail/ahmpjcflkgiildlgicmcieglgoilbfdp 安装 进入edge插件管理页面 edge://extensions/2. 将下载的crt文件拖到这个页面&#xff0c;就能自动安装了 在其他网页不能安装&#xff0c;会变成下载。

压缩感知常用的测量矩阵

测量矩阵的基本概念 在压缩感知&#xff08;Compressed Sensing&#xff0c;CS&#xff09;理论中&#xff0c;测量矩阵&#xff08;也称为采样矩阵&#xff09;是实现信号压缩采样的关键工具。它是一个通常为非方阵的矩阵&#xff0c;用于将信号从高维空间映射到低维空间&…

calcite在flink中的二次开发,介绍解析器与优化器

calcite 在flink中的二次开发 1 CodeGen2 flink 语法扩展2.1 在进行 Rule 规则匹配时&#xff0c;放开对 Distinct 的限制2.2下面附上一个 利用codegen来生成所需类的例子&#xff1a; 3 flink使用calcite 生成解析器FlinkSqlParserImpl3.1 FlinkSqlParserImpl 的生成3.1.1 fli…

尝试一下最新的联合办公利器ONLYOffice

下载下来一起试试吧 桌面安装版下载地址&#xff1a;https://www.onlyoffice.com/zh/download-desktop.aspx) 官网地址&#xff1a;https://www.onlyoffice.com 普通Office对联合办公的局限性 普通Office软件&#xff08;如Microsoft Office、Google Docs等&#xff09;在面对…

shell脚本实现菜单案例......

系统命令&#xff1a; $REPLY : 当没有参数变量提供给read命令的时候&#xff0c;这个变量会作为默认变量提供给read命令 1.select命令写菜单 #!/bin/bash PS3"please input your choice>>>:" select MENU in {A..E};docase $REPLY inA)date;;B)pwd;;C)who…

OpenCV-42 直方图均匀化

目录 一、直方图均匀化原理 二、直方图均匀化在OpenCV中的运用 一、直方图均匀化原理 直方图均匀化是通过拉伸像素强度的分布范围&#xff0c;使得在0~255灰阶上的分布更加均匀&#xff0c;提高图像的对比度。达到改善图像主管视觉效果的目的。对比度较低的图像适合使用直方…

Adobe将类ChatGPT集成到PDF中

2月21日&#xff0c;全球多媒体巨头Adobe在官网宣布&#xff0c;推出生成式AI助手AI Assistant&#xff0c;并将其集成在Reader 和Acrobat 两款PDF阅读器中。 据悉&#xff0c;AI Assistant的功能与ChatGPT相似&#xff0c;可以基于PDF文档提供摘要、核心见解、基于文档内容&a…
推荐文章