从零开始学习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>() {
                @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();
          }
      }
      

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024光伏展

2024年光伏展是一个专业的光伏行业展览会&#xff0c;旨在展示最新的光伏技术和产品&#xff0c;并促进光伏行业的发展和合作。 该展览会预计将吸引来自全球各地的光伏制造商、供应商、投资者和专业人士。参展的公司将有机会展示他们的最新产品和技术&#xff0c;与其他行业领导…

力扣238和169

一&#xff1a;238. 除自身以外数组的乘积 1.1题目 1.2思路 1.3代码 //左右乘表 int* productExceptSelf(int* nums, int numsSize, int* returnSize) {int* answer (int*)malloc(numsSize*sizeof(int));int i 0;int left[numsSize],right[numsSize];left[0] 1;for(i 1;…

04 Aras Innovator二次开发-客户端方法

客户端方法为JS方法。 系统提供了很多触发点&#xff0c;可以嵌入客户端方法&#xff0c;如下&#xff1a; 1 对象类的客户端事件页签&#xff1a; 2 窗体的Form Event和Filed Event 3.关系类的网格事件&#xff1a; 4 属性事件&#xff1a; 5.可自定义Action,触发客户端事件…

剑桥大学强推!一本超硬核的机器学习教材书!(449页中英文pdf下载)

今天给同学们推荐一本专为高级本科生或刚毕业的学生设计的机器学习教材——《理解机器学习&#xff1a;从理论到算法》。 这本教材的内容十分丰富&#xff0c;但没有陷入“科普”式的堆砌材料的写作方式&#xff0c;由于作者是该领域的权威专家&#xff0c;因此在介绍各种理论…

⭐北邮复试刷题LCR 037. 行星碰撞__栈 (力扣119经典题变种挑战)

LCR 037. 行星碰撞 给定一个整数数组 asteroids&#xff0c;表示在同一行的小行星。 对于数组中的每一个元素&#xff0c;其绝对值表示小行星的大小&#xff0c;正负表示小行星的移动方向&#xff08;正表示向右移动&#xff0c;负表示向左移动&#xff09;。每一颗小行星以相…

天锐绿盾 | 文件数据\资料防泄漏软件 \ 自动智能透明加密保护

怎么防止公司办公终端文件数据资料外泄? 防止公司办公终端文件数据资料外泄是非常重要的&#xff0c;以下是一些有效的措施&#xff1a; 限制访问权限&#xff1a;根据员工的职责和需求&#xff0c;设定文件和数据资料的访问权限。确保只有授权人员才能访问敏感信息。 加密存…

JAVA高并发——单例模式和不变模式

文章目录 1、探讨单例模式2、不变模式 由于并行程序设计比串行程序设计复杂得多&#xff0c;因此我强烈建议大家了解一些常见的设计方法。就好像练习武术&#xff0c;一招一式都是要经过学习的。如果自己胡乱打&#xff0c;效果不见得好。前人会总结一些武术套路&#xff0c;对…

Flink理论—容错之状态后端(State Backends)

Flink理论—容错之状态后端(State Backends) Flink 使用流重放和 检查点的组合来实现容错。检查点标记每个输入流中的特定点以及每个运算符的相应状态。通过恢复运算符的状态并从检查点点重放记录&#xff0c;可以从检查点恢复流数据流&#xff0c;同时保持一致性 容错机制不…

Git笔记——1

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 Git安装_centos 创建本地仓库 配置本地仓库 添加文件——场景一 查看.git文件 添加文件——场景二 修改文件 版本回退 总结 前言 世上有两种耀眼的光芒&#…

基于Java (spring-boot)的社区物业管理系统

一、项目介绍 本系统共分为两个角色&#xff1a;管理员和业主。 主要功能有&#xff0c;核心业务处理&#xff0c;基础信息管理&#xff0c;数据统计分析 核心业务处理&#xff1a;车位收费管理&#xff0c;物业收费管理&#xff0c;投诉信息管理&#xff0c;保修信息管理。 …

大数据计算技术秘史(上篇)

在之前的文章《2024 年&#xff0c;一个大数据从业者决定……》《存储技术背后的那些事儿》中&#xff0c;我们粗略地回顾了大数据领域的存储技术。在解决了「数据怎么存」之后&#xff0c;下一步就是解决「数据怎么用」的问题。 其实在大数据技术兴起之前&#xff0c;对于用户…

什么是HTTP代理,socks5代理?它们的区别是什么?

什么是HTTP代理&#xff1f; HTTP代理是一种常见的网络代理方式&#xff0c;它通过在客户端和服务器之间建立一个中间层&#xff0c;将客户端的请求转发给服务器&#xff0c;并将服务器的响应返回给客户端。HTTP代理通常用于访问受限制的网站&#xff0c;或者在网络中隐藏客户…

NestJS入门9:管道入门

前文参考 NestJS入门1&#xff1a;创建项目 NestJS入门2&#xff1a;创建模块 NestJS入门3&#xff1a;不同请求方式前后端写法 NestJS入门4&#xff1a;MySQL typeorm 增删改查 NestJS入门5&#xff1a;加入Swagger NestJS入门6&#xff1a;日志中间件 NestJS入门7&…

HTTP REST 方式调用WebService接口(wsdl)

一、WebService接口正常使用SOAP协议调用&#xff0c;测试时常采用SoapUI软件调用&#xff0c;具体如下&#xff1a; 二、由于目前主流web服务逐渐转换为RESTful的形式&#xff0c;且SOAP协议的实现也是基于HTTP协议&#xff0c;故存在通过HTTP调用WebService接口的可能 2.1 …

嵌入式I2C 信号线为何加上拉电阻(图文并茂)

IIC 是一个两线串行通信总线&#xff0c;包含一个 SCL 信号和 SDA 信号&#xff0c;SCL 是时钟信号&#xff0c;从主设备发出&#xff0c;SDA 是数据信号&#xff0c;是一个双向的&#xff0c;设备发送数据和接收数据都是通过 SDA 信号。 在设计 IIC 信号电路的时候我们会在 SC…

分组统计

目录 分组统计 根据部门编号分组&#xff0c;查询每个部门的编号、人数、平均工资 根据职位分组&#xff0c;统计出每个职位的人数、最低工资与最高工资 如果查询不使用 GROUP BY 子句&#xff0c;那么 SELECT 子句中只允许出现统计函数&#xff0c;其他任何字段不允许出现…

Git笔记——2

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、撤销修改__情况一 二、撤销修改__情况二 三、撤销修改__情况三 四、删除文件 五、理解分支 六、创建、切换和合并分支初体验 七、删除分支 八、合并冲突 总…

java程序流程控制

java程序有哪些流程控制、以及Java提供了哪些方案来控制程序的执行顺序&#xff1f; 程序的流程控制一般分为3种&#xff1a;顺序结构、分支结构、循环结构 顺序结构&#xff1a;就是不加任何控制&#xff0c;代码从main方法开始自上而下执行 分支结构&#xff1a;就是根据条…

crontab history查看命令的执行时间

crontab crontab学习网站&#xff08;19. crontab 定时任务 — Linux Tools Quick Tutorial&#xff09; 例子 今天实际工作里用到的&#xff08;已经进行了防信息泄露处理 比如我现在希望每周三上午10:00之行一个php脚本 --gpt生成 00 10 * * 3 cd /home/user/project/r…

Python开源项目周排行 2024年第4周

#2024年第4周2024年2月18日1Awesome-LLM一个精选的大型语言模型 (LLM) 资源列表&#xff0c;涵盖了以下内容&#xff1a; LLM 模型介绍 论文和代码 部署工具 应用场景 教程和示例 Awesome-LLM 的目标是帮助人们了解和使用 LLM 技术&#xff0c;并为 LLM 开发人员提供一个资源中…