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

news2025/2/2 4:54:13

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>() {
                @Override
                public 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>() {
                  @Override
                  public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                      Files.delete(file); // 删除文件
                      logger.error("delete file: {}", file);
                      return FileVisitResult.CONTINUE;
                  }
                  @Override
                  public 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.coloradmin.cn/o/1462986.html

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

相关文章

docker自定义网络实现容器之间的通信

Background docker原理 docker是一个Client-Server结构的系统&#xff0c;Docker的守护进程运行在主机上。通过Socket从客户端访问。docker核心三大组件&#xff1a;image–镜像、container-容器、 repository-仓库。docker使用的cpu、内存以及系统内核等资源都是直接使用宿主…

C语言字符串函数strchr与strrchr

注意&#xff1a; 这两个函数的功能&#xff0c;都是在指定的字符串 s 中&#xff0c;试图找到字符 c。strchr() 从左往右找&#xff0c;strrchr() 从右往左找。字符串结束标记 ‘\0’ 被认为是字符串的一部分。 示例 char *p;p strchr("www.qq.com", .); // 从左…

rtsp推拉流

1.搭建视频服务器 smart-rtmpd: smart_rtmpd 是一款 rtmp、rtsp 服务器&#xff0c;非常好用&#xff0c;解压既运行&#xff0c;支持跨平台&#xff0c;无任何依赖&#xff0c;性能和 SRS 相比不分上下 2.推拉流 下载windows版本ffmpeg,并设置环境变量. 推流 ffmpeg -re -st…

sentinel中监听器的运用--规则管理

sentinel中监听器的运用–规则管理 规则结构 类图关系 类关系图如下 Rule 将规则抽象成一个类, 规则与资源是紧密关联的, 也就是说规则作用于资源。因此, 我们需要将规则表示为一个类, 并包含一个获取资源的方法 这里采用接口的原因就是规则是一个抽象概念而非具体实现。…

护眼灯减蓝光和无蓝光的区别是什么?盘点回购率前5名的护眼台灯!

随着近视问题日益严重&#xff0c;保护视力已逐渐成为公众关注的焦点。在日常生活中&#xff0c;不良的光线环境常常成为视力下降的潜在威胁&#xff0c;因此&#xff0c;护眼台灯成为了现代家庭保护视力的必备工具。其中&#xff0c;关于台灯的蓝光问题更是受到了广泛关注。有…

YOLOv9来了! 使用可编程梯度信息学习你想学的内容, v7作者新作!【文献速读】

YOLOv9文献速读&#xff0c;本文章使用 GPT 4.0 和 Ai PDF 工具完成。 文章地址&#xff1a;https://arxiv.org/pdf/2402.13616.pdf 文章目录 文章简介有哪些相关研究&#xff1f;如何归类&#xff1f;谁是这一课题在领域内值得关注的研究员&#xff1f;论文试图解决什么问题&a…

STM32—启用按键

​ 目录 1 、电路构成及原理图 2、编写实现代码 main.c main.h key.c 3、代码讲解 4、 烧录到开发板调试、验证代码 5、检验效果 本人使用的是朗峰 STM32F103 系列开发板&#xff0c;此笔记基于这款开发板记录。 1 、电路构成及原理图 重要&#xff01;一定先用短路…

解决Uncaught SyntaxError: Cannot use import statement outside a module(at XXX)报错

报错原因&#xff1a;这个错误通常是因为你正在尝试在一个不支持 ES6 模块语法的环境中使用 import 语句。这可能是因为你的代码是在一个只支持 CommonJS 或 AMD 模块系统的环境中运行的&#xff0c;或者你的代码运行的环境没有正确配置以支持 ES6 模块。如果是在浏览器环境&am…

Predis Multi-Zone

A Data Flow Framework with High Throughput and Low Latency for Permissioned Blockchains 联盟链的吞吐瓶颈由共识层和网络层的数据分发过程共同决定。 Predis 协议利用了共识节点的空闲带宽&#xff0c;提前分发区块中的内容即bundle&#xff0c;减少了共识区块中的内容&…

服务器运维小技巧(三)——如何进行服务器批量管理

运维工程师在进行服务器运维时&#xff0c;往往一个人要同时监控几十甚至成百上千的机器&#xff0c;当机器数量增加时&#xff0c;服务器管理的难度将会大大增加。很多工程师在工作中会使用一些运维面板&#xff0c;比如bt&#xff0c;1panel等&#xff0c;但是这些工具往往一…

力扣 面试题 05.06. 整数转换

思路&#xff1a; 牵扯到二进制数&#xff0c;基本上要考虑位运算符&#xff0c;相关知识可以见http://t.csdnimg.cn/fzts7 之前做过类似的题目&#xff0c;大致思路就是先用按位异或^找出不同位&#xff0c;再用n&&#xff08;n-1&#xff09;计算出不同位的个数&#x…

利用Dynamo辅助设置项目浏览器——替换视图名称及子规程

前言 今天的案例&#xff0c;来自群友长不大的唐三岁&#xff0c;他自己也一直在学习Dynamo&#xff0c;同时他希望把自己的学习成果分享出来&#xff0c;本期带来的&#xff0c;就是他自己的研究成果&#xff1a; 视图名称统一替换及视图子规程自动添加 先给大家看一段视频&…

通信入门系列——线性空间理论知识

微信公众号上线&#xff0c;搜索公众号小灰灰的FPGA,关注可获取相关源码&#xff0c;定期更新有关FPGA的项目以及开源项目源码&#xff0c;包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 本节目录 一、线性空间 1、欧几里…

Docker本地部署Rss订阅工具并实现公网远程访问

文章目录 1. Docker 安装2. Docker 部署Rsshub3. 本地访问Rsshub4. Linux安装Cpolar5. 配置公网地址6. 远程访问Rsshub7. 固定Cpolar公网地址8. 固定地址访问 Rsshub是一个开源、简单易用、易于扩展的RSS生成器&#xff0c;它可以为各种内容生成RSS订阅源。 Rsshub借助于开源社…

Android Studio创建项目时gradle下载慢

先停止当前Sync&#xff0c;找到gradle-wrapper.properties文件&#xff0c;将distributionUrl修改为腾讯镜像源&#xff1a; distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-6.5-bin.zip

Java 学习和实践笔记(16):类的理解以及初始值

类&#xff0c;英文名叫class。基本上对应的就是语言里的名词。 比如&#xff0c;房子、人、树、花、汽车等等&#xff0c;这些名词&#xff0c;这些可以定义成类。 以房子为例&#xff0c;作为一个房子&#xff0c;它一定有相应的属性&#xff0c;比如房顶、墙、门、窗等等&…

ElasticSearch DSL查询、排序 、分页的原理及语法

1. DSL查询分类和基本语法 ElasticSearch提供了基于Json的DSL来定义查询&#xff0c;常见的查询类型包括&#xff1a; • 查询所有&#xff1a;查询出所有数据&#xff0c;一般测试用&#xff0c;一般不是查出所有&#xff0c;一次性查询20条。例如 match_all • 全文检索(ful…

『智能遥控新境界』:远程控制APP,高效生活的秘诀!

在这个科技日新月异的时代&#xff0c;我们的生活被各种手机软件所包围。几乎每个人都有一个甚至多个手机&#xff0c;你是否也有遇到过需要远程操作自己某一台手机的场景呢&#xff1f;今天&#xff0c;我要向大家推荐一款神奇的手机远程操作神器&#xff0c;让你可以随时随地…

基于 java springboot+layui仓库管理系统

基于 java springbootlayui仓库管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源…

力扣102 二叉树的层序遍历 Java版本

文章目录 题目描述思路代码 题目描述 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[…