NIO三大组件 Channel 之 FileChannel 的使用

FileChannel

获取方法
  • 通过 FileInputStream 获取 channel 只能读操作
  • 通过FileOutputStream 获取 channel 只能写操作
  • 通过 RandomAccessFile 是否能读取根据构造的 RandomAccessFile 读写模式决定
// RandomAccessFile 方法中的第二个参数就是 决定是否 可读写操作
// 可读
FileChannel channel = new RandomAccessFile("words.txt", "r").getChannel()
// 可写
FileChannel channel = new RandomAccessFile("words.txt", "w").getChannel()
// 可读写
FileChannel channel = new RandomAccessFile("words.txt", "rw").getChannel()
FileChannel from = new FileInputStream("H:\\AE+2020最新版(6月份).rar").getChannel();
FileChannel to = new FileOutputStream("H:\\AE+2020.rar").getChannel())
操作方法
  • read  读方法
  • write 写方法
  • close  关闭方法
  • position  获取当前的指针位置
  • size 获取文件的大小
  • transferTo  拷贝数据
代码案例
public static void fileApi() {

        try {

            FileChannel from = new FileInputStream("data.txt").getChannel();
            FileChannel to = new FileOutputStream("to.txt").getChannel();

            ByteBuffer buffer = ByteBuffer.allocate(2);

            long size = from.size();
            log.debug("文件的大小:{}",size);


            for (long remaining = size;remaining>0;){
                // 从 from 通道内 读取数据 并写入 buffer
                int read = from.read(buffer);

                // 查看 from 当前指针指向的位置
                long position = from.position();
                log.debug("当前的位置:{}",position);

                // 将 buffer 切换为读模式
                buffer.flip();
                // buffer 中的数据读取并写入 to 通道
                int write = to.write(buffer);
                // 清空 buffer中 所有的数据
                buffer.clear();

                //剩余数据量 =  总数 - 已经读取的数据量
                remaining = remaining - read;
            }

            from.close();
            to.close();



            // todo 效率高,底层会利用操作系统的 零拷贝 进行优化,传输数据有上限
            for (long residue = size; residue > 0;) {
                log.debug("以读数:{},剩余数:{}",size - residue, residue);
                residue -= from.transferTo(size - residue, residue, to);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
打印结果

Path 和 Paths yi'ji

  • Path 用来表示文件路径
  • Paths 是工具类,用来获取 Path 实例
Path source = Paths.get("1.txt"); // 相对路径 使用 user.dir 环境变量来定位 1.txt

Path source = Paths.get("d:\\1.txt"); // 绝对路径 代表了  d:\1.txt

Path source = Paths.get("d:/1.txt"); // 绝对路径 同样代表了  d:\1.txt

Path projects = Paths.get("d:\\data", "projects"); // 代表了  d:\data\projects

File 和 Files

常用方法
  • exists()检查文件是否存在
  • createDirectory()  创建一级目录
  • createDirectories()  创建多级目录用
  • copy()  拷贝文件
  • move()  移动文件
  • delete() 删除文件/删除目录
代码案列
// exists
Path path = Paths.get("helloword/data.txt");
System.out.println(Files.exists(path));

// createDirectory
Path path = Paths.get("helloword/d1");
Files.createDirectory(path);

//如果目录已存在,会抛异常 FileAlreadyExistsException
//不能一次创建多级目录,否则会抛异常 NoSuchFileException

// createDirectories
Path path = Paths.get("helloword/d1/d2");
Files.createDirectories(path);

// copy
Path source = Paths.get("helloword/data.txt");
Path target = Paths.get("helloword/target.txt");
Files.copy(source, target);
// 如果希望用 source 覆盖掉 target,需要用 StandardCopyOption 来控制
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

// move
Path source = Paths.get("helloword/data.txt");
Path target = Paths.get("helloword/data.txt");
// StandardCopyOption.ATOMIC_MOVE 保证文件移动的原子性
Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);

// delete 文件
Path target = Paths.get("helloword/target.txt");
Files.delete(target);
// 如果文件不存在,会抛异常 NoSuchFileException


// delete 目录
Path target = Paths.get("helloword/d1");
Files.delete(target);
// 如果目录还有内容,会抛异常 DirectoryNotEmptyException
遍历多级目录以及文件
代码案列
/**
     * 遍历多级目录以及其中的文件
     * @throws IOException
     */
    private static void m1() throws IOException {
        //todo 计数器
        AtomicInteger dirCount = new AtomicInteger();
        AtomicInteger fileCount = new AtomicInteger();


        Files.walkFileTree(Paths.get("D:\\java\\jdk8"), new SimpleFileVisitor<>() {

            // todo 访问一个目录,在进入之前调用
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                dirCount.incrementAndGet();
                log.debug("访问一个目录,在进入之前调用:{}",dir.toString());
                return super.preVisitDirectory(dir, attrs);
            }

            // todo 文件被访问时被调用。该文件的文件属性被传递给这个方法
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                if(file.toString().endsWith(".jar")){
                    fileCount.incrementAndGet();
                    log.debug("文件被访问时被调用:{}",file.toString());
                }
                return super.visitFile(file, attrs);
            }


            // todo  一个目录的所有节点都被访问后调用。遍历时跳过同级目录或有错误发生,Exception会传递给这个方法
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                log.debug("一个目录的所有节点都被访问后调用:{}",dir.toString());
                return super.postVisitDirectory(dir, exc);
            }


            //todo 当文件不能被访问时,此方法被调用。Exception被传递给这个方法。
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                log.debug("当文件不能被访问时,此方法被调用",file.toString());
                return super.visitFileFailed(file, exc);
            }
        });

        log.debug("dirCount:{}", dirCount.get());
        log.debug("fileCount:{}", fileCount.get());

        // todo  https://segmentfault.com/a/1190000020778836 博客中有更多的操作方法
    }
删除多级目录以及文件
代码案例
/**
     * 删除多级目录文件
     * @throws IOException
     */
    private static void delete() throws IOException {
        // todo 删除多级目录文件,只需要在 进入目录之后删除所有文件,删除所有文件之后 出来删除 目录
        Files.walkFileTree(Paths.get("D:\\java\\jdk8 - 副本"),new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                return super.preVisitDirectory(dir, attrs);
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // todo  删除文件
                Files.delete(file);
                return super.visitFile(file, attrs);
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return super.visitFileFailed(file, exc);
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                // todo 删除目录
                Files.delete(dir);
                return super.postVisitDirectory(dir, exc);
            }
        });
    }
拷贝多级目录以及文件
代码案例
public static void main(String[] args) throws IOException {
        String source = "D:\\gradle-8.11.1";
        String target = "D:\\gradle-8.11.1aaa";



        /**
         * 拷贝 多级目录文件
         */
        Files.walk(Paths.get(source)).forEach(path -> {
            try {
                // todo 将遍历到的目录名 或者 文件名  替换成新的
                String targetName = path.toString().replace(source, target);
                //如果是目录,则创建
                if(Files.isDirectory(path)){
                    Files.createDirectory(Paths.get(targetName));
                }else if(Files.isRegularFile(path)){
                    Files.copy(path,Paths.get(targetName));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });



    }

更多方法参考

Java 文件操作指南:Path、Paths 与 Files_java paths-优快云博客

https://segmentfault.com/a/1190000020778836

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值