java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java文件复制

基于Java IO API实现文件复制工具

作者:Cache技术分享

这篇文章主要为大家详细介绍了如何基于Java IO API实现文件复制工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

 Java IO API - Java 文件复制工具

这是一个用 Java 编写的递归文件复制工具,模仿了文件系统复制的操作。它从源目录复制文件到目标目录,并支持指定复制的最大目录层级(-depth)。

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.EnumSet;
import java.util.stream.Stream;
import static java.nio.file.FileVisitResult.CONTINUE;
import static java.nio.file.FileVisitResult.SKIP_SUBTREE;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
 * Sample code that copies files recursively 
 * from a source directory to a destination folder.
 * The maximum number of directory levels to copy 
 * is specified after -depth.
 * The number of files copied is printed
 * to standard out.
 * You can execute the application using:
 * @code java Copy . new -depth 4
 */
public class Copy {
    /**
     * A {@code FileVisitor} that finds
     * all files that match the
     * specified pattern.
     */
    public static class Replicator
            extends SimpleFileVisitor<Path> {
        Path source;
        Path destination;
        public Replicator(Path source, Path destination) {
            this.source = source;
            this.destination = destination;
        }
        // Prints the total number of
        // files copied to standard out.
        void done() throws IOException {
            try (Stream<Path> path = Files.list(Paths.get(destination.toUri()))) {
                System.out.println("Number of files copied: "
                        + path.filter(p -> p.toFile().isFile()).count());
            }
        }
        // Copy a file in destination
        @Override
        public FileVisitResult visitFile(Path file,
                                         BasicFileAttributes attrs) {
            System.out.println("Copy file: " + file);
            Path newFile = destination.resolve(source.relativize(file));
            try{
                Files.copy(file,newFile);
            }
            catch (IOException ioException){
                //log it and move
            }
            return CONTINUE;
        }
        // Invoke copy of a directory.
        @Override
        public FileVisitResult preVisitDirectory(Path dir,
                                                 BasicFileAttributes attrs) {
            System.out.println("Copy directory: " + dir);
            Path targetDir = destination.resolve(source.relativize(dir));
            try {
                Files.copy(dir, targetDir, REPLACE_EXISTING, COPY_ATTRIBUTES);
            } catch (IOException e) {
                System.err.println("Unable to create " + targetDir + " [" + e + "]");
                return SKIP_SUBTREE;
            }
            return CONTINUE;
        }
        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            if (exc == null) {
                Path destination = this.destination.resolve(source.relativize(dir));
                try {
                    FileTime time = Files.getLastModifiedTime(dir);
                    Files.setLastModifiedTime(destination, time);
                } catch (IOException e) {
                    System.err.println("Unable to copy all attributes to: " + destination + " [" + e + "]");
                }
            } else {
                throw exc;
            }
            return CONTINUE;
        }
        @Override
        public FileVisitResult visitFileFailed(Path file,
                                               IOException exc) {
            if (exc instanceof FileSystemLoopException) {
                System.err.println("cycle detected: " + file);
            } else {
                System.err.format("Unable to copy:" + " %s: %s%n", 
                        file, exc);
            }
            return CONTINUE;
        }
    }
    static void usage() {
        System.err.println("java Copy <source> <destination>" +
                " -depth \"<max_level_dir>\"");
        System.exit(-1);
    }
    public static void main(String[] args)
            throws IOException {
        if (args.length < 4 || !args[2].equals("-depth"))
            usage();
        Path source = Paths.get(args[0]);
        Path destination = Paths.get(args[1]);
        int depth = Integer.parseInt(args[3]);
        Replicator walk = new Replicator(source, destination);
        EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        Files.walkFileTree(source, opts, depth, walk);
        walk.done();
    }
}

功能简介

该程序会:

例如:

$ java Copy . new -depth 4

会把当前目录及其子目录(最多 4 层)中的文件复制到 new 目录。

示例代码结构详解

main()方法:程序入口

public static void main(String[] args) throws IOException {
    if (args.length < 4 || !args[2].equals("-depth"))
        usage();

    Path source = Paths.get(args[0]);
    Path destination = Paths.get(args[1]);
    int depth = Integer.parseInt(args[3]);

    Replicator walk = new Replicator(source, destination);
    EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
    Files.walkFileTree(source, opts, depth, walk);
    walk.done();
}

Replicator类:文件复制核心逻辑

public static class Replicator extends SimpleFileVisitor<Path> {

该类继承 SimpleFileVisitor<Path> 并重写了几个关键方法来执行复制操作。

构造方法:初始化源路径与目标路径

public Replicator(Path source, Path destination) {
    this.source = source;
    this.destination = destination;
}

visitFile()方法:复制文件

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    System.out.println("Copy file: " + file);
    Path newFile = destination.resolve(source.relativize(file));
    try {
        Files.copy(file, newFile);
    } catch (IOException ioException) {
        // 错误日志处理
    }
    return CONTINUE;
}

preVisitDirectory()方法:复制目录

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
    System.out.println("Copy directory: " + dir);
    Path targetDir = destination.resolve(source.relativize(dir));
    try {
        Files.copy(dir, targetDir, REPLACE_EXISTING, COPY_ATTRIBUTES);
    } catch (IOException e) {
        System.err.println("Unable to create " + targetDir + " [" + e + "]");
        return SKIP_SUBTREE;
    }
    return CONTINUE;
}

postVisitDirectory()方法:复制目录属性

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
    if (exc == null) {
        Path destination = this.destination.resolve(source.relativize(dir));
        try {
            FileTime time = Files.getLastModifiedTime(dir);
            Files.setLastModifiedTime(destination, time);
        } catch (IOException e) {
            System.err.println("Unable to copy all attributes to: " + destination + " [" + e + "]");
        }
    } else {
        throw exc;
    }
    return CONTINUE;
}

visitFileFailed()方法:错误处理

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    if (exc instanceof FileSystemLoopException) {
        System.err.println("Cycle detected: " + file);
    } else {
        System.err.format("Unable to copy: %s: %s%n", file, exc);
    }
    return CONTINUE;
}

done()方法:统计已复制文件数

void done() throws IOException {
    try (Stream<Path> path = Files.list(Paths.get(destination.toUri()))) {
        System.out.println("Number of files copied: "
                + path.filter(p -> p.toFile().isFile()).count());
    }
}

在文件复制完成后,统计并打印成功复制的文件数。

usage()方法:程序使用说明

static void usage() {
    System.err.println("java Copy <source> <destination> -depth \"<max_level_dir>\"");
    System.exit(-1);
}

如果输入参数无效,打印使用说明并退出程序。

扩展思路与练习建议

扩展功能实现方法
复制文件时跳过某些类型visitFile() 方法中加入文件类型判断(如跳过 .txt 文件)
并行复制大文件夹使用 ExecutorService 执行并行文件复制
复制过程中显示进度条使用 System.out.print 打印进度信息
按文件类型筛选复制visitFile() 中加入文件类型过滤,例如只复制 .java 文件
备份和版本控制visitFile() 中实现版本号控制,避免覆盖旧版本

错误处理建议

小结

这个 Copy 示例演示了如何使用 Java 的 nio 包进行递归文件复制。通过自定义 FileVisitor 类,你可以实现高效且灵活的文件操作。这个工具可以被扩展和定制化,满足各种实际项目中的需求。

到此这篇关于基于Java IO API实现文件查找和复制工具的文章就介绍到这了,更多相关Java文件查找和复制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文