首页 > 编程语言 >Netty(二)文件编程

Netty(二)文件编程

时间:2023-11-13 15:11:31浏览次数:31  
标签:Files Netty Paths 文件 编程 IOException new public channel

Netty(二)文件编程


1 FileChannel

  • 不能够直接打开FileChannel,只能够通过FileInputStreamFIleOutPutStreamRandomAccessFile的getChannel()方法来获取FileChannel
  • FileInputStream获得的channel只能读
  • FIleOutPutStream获得的channel只能写
  • RandomAccessFile是否能读写需要根据构造RandomAccessFile时的读写模式决定
1.1 读取
  • read会从channel中读取数据填充到ByteBuffer中,然后返回读取了多少字节的数量,-1表示文件读取结束

            try (FileChannel channel = new RandomAccessFile("words", "r").getChannel()){
                ByteBuffer buffer = ByteBuffer.allocate(100);
    //            19
                int read = channel.read(buffer);
                System.out.println(read);
                debugAll(buffer);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
    
1.2 写入
  • channel的写入能力是有限的,因此channel的write不能够保证ByteBuffer中的全部数据一次性写入

  • 因此正确的写入的姿势如下,需要使用hasRemaining判断bytebuffer有没有剩余数据:

        @Test
        public void fileChannelWriteTest() {
            try (FileChannel channel = new RandomAccessFile("words", "rw").getChannel()) {
                ByteBuffer byteBuffer = ByteBuffer.allocate(11);
                byteBuffer.put("hello world".getBytes());
                // 切换为读模式
                byteBuffer.flip();
                while(byteBuffer.hasRemaining()) {
                    channel.write(byteBuffer);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
1.3 关闭

​ channel必须关闭,并且调用FileInputStreamFIleOutPutStreamRandomAccessFile的close方法后会间接调用channel的close方法

1.4 位置
  • position()获取当前位置,position(index)设置channel的position指针

        public static void main(String[] args) {
            try (FileChannel channel = new RandomAccessFile("words", "r").getChannel()){
                ByteBuffer buffer = ByteBuffer.allocate(100);
                int read = channel.read(buffer);
    //            11
                System.out.println(channel.position());
    //            12
                channel.position(12);
                System.out.println(channel.position());
    
    //            debugAll(buffer);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
1.5 大小
  • channel.size()获取文件大小

        public static void main(String[] args) {
            try (FileChannel channel = new RandomAccessFile("words", "r").getChannel()){
    //            11
                System.out.println(channel.size());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
1.6 强制写入
  • 操作系统出于性能的考虑会将数据缓存而不是立刻写入磁盘,可以调用channel.force(true)方法立刻将文件内容写入磁盘,参数true表示同时写入文件的元数据信息(文件的权限等信息)

        @Test
        public void fileChannelWriteTest() {
            try (FileChannel channel = new RandomAccessFile("words", "rw").getChannel()) {
                ByteBuffer byteBuffer = ByteBuffer.allocate(11);
                byteBuffer.put("hello world".getBytes());
                // 切换为读模式
                byteBuffer.flip();
                while(byteBuffer.hasRemaining()) {
                    channel.write(byteBuffer);
                    channel.force(true);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
1.7 FileChannel数据传输
  • FileChannel的文件船速速率要高于流传输,因为会操作系统底层的零拷贝进行优化

        @Test
        public void testFileChannelTransferTo() {
            try (
                    FileChannel from = new FileInputStream("words").getChannel();
                    FileChannel to = new FileOutputStream("wordsTo").getChannel();
            ) {
                from.transferTo(0, from.size(), to);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    
  • 但是传输大小上限为2g,如果想要传输大文件,需要进行多次传输

        @Test
        public void testFileChannelTransferTo() {
            try (
                    FileChannel from = new FileInputStream("words").getChannel();
                    FileChannel to = new FileOutputStream("wordsTo").getChannel();
            ) {
                long size = from.size();
                for (var left = size; left > 0; ) {
                    left -= from.transferTo(size - left, left, to);
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    

2 Path & Files

2.1 Path

​ jdk7引入了Path和Paths

  • Path用来表示文件路径

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

    	Path source = Paths.get("1.txt"); 
    
  • path.normalize():格式化路径,防止出现相对路径..的写法

2.2 Files
  • Fles.exists:检查文件是否存在

        @Test
        public void testFiles() {
            var path = Paths.get("helloWorld.txt");
            // false
            System.out.println(Files.exists(path));
        }
    
  • Files.createDirectory():创建一级目录

        @Test
        public void testFiles() {
            var path = Paths.get(".\\HelloWorld");
            try {
                Files.createDirectory(path);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
    • 如果文件已经存在,会抛出FileAlreadyExistsException
    • 如果创建了多级目录,则会抛出NoSuchFileException,意思是没有一级目录
  • Files.createDirectories:创建多级目录

        @Test
        public void testFiles() {
            var path = Paths.get(".\\HelloWorld\\d");
            try {
                Files.createDirectories(path);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
  • Files.copy(source, target):文件拷贝

    • 如果目标文件已经存在则会抛出FileAlreadyExistsException

    • 如果希望覆盖掉target,则可以使用StandardCopyOption来控制

          @Test
          public void testFiles() {
              var source = Paths.get("words");
              var target = Paths.get("wordsTo");
      
              try {
                  Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
              } catch (IOException e) {
                  throw new RuntimeException(e);
              }
          }
      
  • Files.move(source, target):文件移动

    • 需要目标路径存在
    • ATOMIC_MOVE能够保证移动操作的原子性
        @Test
        public void testFiles() {
            var source = Paths.get("words");
            var target = Paths.get("Hello\\wordsTo");
    
            try {
                Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
  • Files.delete(source):删除文件或者目录

    • 如果文件不存在,则会抛出NoSuchFileException
    • 如果目录中还有内容,则会抛出DirectoryNotEmptyException
        @Test
        public void testFiles() {
            var source = Paths.get("words");
            var target = Paths.get("Hello\\wordsTo");
    
            try {
                Files.delete(target);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
2.3 Files文件夹遍历
  • Files.walkFileTree:遍历文件夹下的所有文件和目录

  • 采用访问者模式,即需要传入一个SimpleFileVisitor遍历逻辑由Files实现,而遍历到文件、遍历到文件夹、访问文件失败和遍历文件夹后的操作需要传入一个匿名内部类指定实现

        public static void main(String[] args) throws IOException {
            var path = Paths.get("E:\\Program_workspace\\jdk\\jdk-21.0.1");
            AtomicInteger dirCount = new AtomicInteger();
            AtomicInteger fileCount = new AtomicInteger();
    
            Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    System.out.println(dir);
                    dirCount.incrementAndGet();
                    return super.preVisitDirectory(dir, attrs);
                }
    
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println(file);
                    fileCount.incrementAndGet();
                    return super.visitFile(file, attrs);
                }
            });
    
            System.out.println(dirCount);
            System.out.println(fileCount);
        }
    

    上面程序在对文件、文件夹计数的时候,必须使用AtomicInteger进行,因为匿名内部类引用的时候必须为final,因此无法使用基本数据类型

2.4 Files删除多级目录
  • 如果直接使用Files.delete()删除需要保证目录下文件为空

  • 可以借助Files.walkFileTree()重写访问文件时和访问文件夹后的方法,删除文件和文件夹即可完成多级目录的删除

  • 程序中的删除是不会走电脑回收站的,谨慎使用

        private static void fileDel() {
            try {
    //            Files.delete(Paths.get("E:\\leidian - 副本"));
                Files.walkFileTree(Paths.get("E:\\\\leidian - 副本"), new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                        System.out.println("====>" + dir);
                        return super.preVisitDirectory(dir, attrs);
                    }
    
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        System.out.println(file);
                        Files.delete(file);
                        return super.visitFile(file, attrs);
                    }
    
                    @Override
                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                        System.out.println("<====" + dir);
                        Files.delete(dir);
                        return super.postVisitDirectory(dir, exc);
                    }
                });
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
2.5 Files多级目录拷贝
    private static void fileCopy() throws IOException {
        var source = "E:\\leidian";
        var target = "E:\\leidian2";

        Files.walk(Paths.get(source)).forEach(path -> {
            String replace = path.toString().replace(source, target);

            try {
                Files.copy(path, Paths.get(replace));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });

    }

标签:Files,Netty,Paths,文件,编程,IOException,new,public,channel
From: https://www.cnblogs.com/tod4/p/17829204.html

相关文章

  • Netty(四)NIO多线程优化
    Netty(四)NIO多线程优化​ 前面的代码都只有一个选择器,没有充分利用多核CPU,因此可以分两组选择器boss:单线程配一个选择器,专门处理accept事件,不负责数据的读写worker:创建CPU核心数的线程,每个线程配一个选择器,轮流处理read事件1多线程问题分析关键是这一部分的代码,需要保......
  • Netty(三)网络编程
    Netty(三)网络编程1阻塞和非阻塞堵塞:在没有数据可读的时候,包括数据复制的过程,线程必须堵塞等待,不会占用CPU但是线程相当于闲置在单线程下,两个堵塞的方法会相互影响,必须使用多线程,32位JVM一个线程320K,64位JVM一个线程1024K,为了减少线程数,需要采用线程池技术但是即便使用了线......
  • node+express服务给前端提供markdown数据,前端渲染md文件在页面上
    本文介绍后端怎么把markdown文件发给前端,前端又怎么渲染在页面中。先看效果图md文件代码: 前端网页渲染: 先介绍node+express怎么提供接口:constexpress=require("express");constrouter=express.Router();constfs=require("fs");router.get("/api/getMark......
  • Java 小文件上传、大文件分片上传、断点续传、秒传的开发原理
    1、前言 文件上传在项目开发中再常见不过了,大多项目都会涉及到图片、音频、视频、文件的上传,通常简单的一个Form表单就可以上传小文件了,但是遇到大文件时比如1GB以上,或者用户网络比较慢时,简单的文件上传就不能适用了,用户辛苦传了好几十分钟,到最后发现上传失败,这样的系统用户体......
  • python 脚本打包成exe可运行文件
    在Python 3中使用Tkinter编写GUI应用程序既简单又有趣。然而,如果你想与其他人分享你的应用程序,那么你需要将源代码和必要的库文件一起打包成一个可执行文件。本文将介绍如何使用pyinstaller将Python 3脚本打包成一个.exe文件并将Tkinter应用程序部署到其他计算机上。安装pyinstal......
  • ubuntu开发之安装QT creater出现文本文件忙解决办法
    问题:问题解析:其实就跟windows下面,该文件已被打开,无法删除是一样的道理。解决办法:①找到该文件被那个进程所进行着指令如下:【可知被2537进程使用】sudofuser文件名②杀死该进程sudokill-9进程号现象:......
  • Linux修改文件名命令是什么?
    Linux命令是用于在Linux操作系统中执行各种任务和操作的指令。在Linux中,提供了很多命令可以帮助我们完成各种各样的操作,比如重启网卡、修改文件名、复制目录或文件等,那么Linux修改文件名命令是什么?我们简单来介绍一下。在Linux系统中,有多种命令可以用来修改文件名。以下是......
  • [EFI]技嘉 Z490 VISION G i5-10500 电脑 Hackintosh 黑苹果引导文件
    硬件配置硬件型号驱动情况主板技嘉Z490VISIONGCLPCcontrollerZ490芯片组)处理器英特尔[email protected]六核已驱动内存16GB(威到DDR42655MHz8GBx2〕已驱动硬盘SSDSC2BB150G7R(150GB/国态硬盘)已驱动显卡AMDRadeonRX580(华硕)已驱动声卡瑞昱@英特尔HighDefini......
  • 问题:类文件具有错误的版本 61.0, 应为 52.0
    1.问题在配置SpringBoot项目时,使用了SpringBoot3,jdk版本为jdk1.8,报错:java:无法访问org.springframework.boot.SpringApplication错误的类文件:/G:/tools/Maven/maven-repository/org/springframework/boot/spring-boot/3.1.2/spring-boot-3.1.2.jar!/org/springframework......
  • Android并发编程高级面试题汇总(含详细解析 二)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......