在Java里开发文件拷贝小工具_Java文件IO基础实战说明

Files.copy() 是 Java 7+ 安全高效拷贝文件的首选,需指定 REPLACE_EXISTING 和 COPY_ATTRIBUTES 参数以避免异常并保留元数据;大文件应退化为带 8KB 缓冲的流式拷贝;目录复制须手动递归;Windows 中文路径需设置 -Dfile.encoding=UTF-8。

Files.copy() 最快实现安全拷贝

Java 7+ 推荐直接用 Files.copy(),它底层自动选择最优路径(比如支持 FileChannel.transferTo() 零拷贝),比手动读写流快且不易出错。关键是要传对参数,否则可能覆盖失败或丢元数据。

  • 必须显式指定 StandardCopyOption.REPLACE_EXISTING,否则目标文件存在时直接抛 FileAlreadyExistsException
  • 若需保留最后修改时间、权限等属性,额外加 StandardCopyOption.COPY_ATTRIBUTES
  • 源路径和目标路径都必须是 Path 类型,别传 StringFile——否则编译不通过
Path src = Paths.get("/tmp/data.txt");
Path dst = Paths.get("/backup/data.txt");
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);

处理大文件时避免 OutOfMemoryError

Files.copy() 拷贝几个 GB 的文件一般没问题,但若在内存受限环境(如嵌入式 JVM 或容器限 256MB)下频繁调用,仍可能触发 GC 压力。此时应退回到带缓冲的流式拷贝,并控制缓冲区大小。

  • 缓冲区设为 8192(8KB)是经验值:太小导致系统调用过多,太大无益反而占堆
  • 务必用 try-with-resources 确保 InputStreamOutputStream 关闭,漏关会导致句柄泄漏
  • 不要用 FileInputStream.read(byte[]) 不检查返回值——它可能只读部分字节,必须循环直到 read() 返回 -1
try (InputStream in = new FileInputStream(src.toFile());
     OutputStream out = new FileOutputStream(dst.toFile())) {
    byte[] buf = new byte[8192];
    int len;
    while ((len = in.read(buf)) != -1) {
        out.write(buf, 0, len);
    }
}

复制目录必须自己递归,Files.copy() 不支持

Files.copy() 只处理单个文件,传入目录会直接抛 IOException:“Unsupported operation: isDirectory”。要复制整个目录树,得手动遍历 + 判断类型 + 创建子目录。

  • Files.walk() 获取所有路径,但注意它默认深度优先且不保证顺序——需先建父目录再建子文件
  • Files.createDirectories() 创建目标路径的父级(它会自动跳过已存在的目录)
  • 对每个源路径

    ,用 Files.isRegularFile() 过滤掉目录,只拷贝文件
Path srcDir = Paths.get("/project/src");
Path dstDir = Paths.get("/backup/src");
Files.walk(srcDir)
     .forEach(srcPath -> {
         Path dstPath = dstDir.resolve(srcDir.relativize(srcPath));
         try {
             if (Files.isRegularFile(srcPath)) {
                 Files.createDirectories(dstPath.getParent());
                 Files.copy(srcPath, dstPath, StandardCopyOption.REPLACE_EXISTING);
             }
         } catch (IOException e) {
             throw new UncheckedIOException(e);
         }
     });

Windows 下中文路径乱码?检查默认字符集

在 Windows 上用 Paths.get("C:\\用户\\文档\\file.txt")InvalidPathException 或拷贝后文件名变问号,大概率是 JVM 启动时没指定文件编码。Java 默认用系统 locale 解析路径字符串,而 Windows 中文版默认是 GBK,但 JVM 8+ 在多数情况下按 UTF-8 解析。

  • 启动命令加 -Dfile.encoding=UTF-8 是最稳妥的解法(尤其当路径来自用户输入或配置文件)
  • 避免拼接路径字符串,一律用 Paths.get(String...),它内部会做平台适配
  • 如果必须用 File 构造器,确保字符串本身是合法 Unicode——别用 new String(bytes, "GBK") 错误解码

真正容易被忽略的是:这个编码问题不会在开发机(UTF-8 环境)暴露,一到客户内网 Windows 机器就崩,而且错误日志里只报“path not found”,得盯住 Paths.get(...).toAbsolutePath() 的输出才能确认是否解析变形。