Java IO API实现文件和目录移动、复制和删除操作

 更新时间:2026年06月15日 09:12:16   作者:Cache技术分享  
这篇文章主要为大家详细介绍了Java IO API实现文件和目录移动、复制和删除操作的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

Java IO API - 移动文件或目录

移动文件或目录是文件系统操作中的常见需求,Java 提供了非常方便的方法来实现这一操作:Files.move()

1. 基本用法

Files.move(sourcePath, targetPath);

这行代码会尝试将 sourcePath 移动到 targetPath,但如果目标路径已存在,move() 方法将抛出 FileAlreadyExistsException

2. 常用选项(CopyOption)

你可以传递多个选项来定制移动操作,这些选项以可变参数(varargs)的形式传入:

Files.move(sourcePath, targetPath, REPLACE_EXISTING, ATOMIC_MOVE);
枚举常量含义说明
REPLACE_EXISTING如果目标已经存在,则替换目标文件或目录。对于符号链接,会替换链接本身。
ATOMIC_MOVE确保以原子方式移动文件,意味着文件在移动过程中不会出现部分完成的状态。

3. 移动目录

  • 空目录可以直接移动。
  • 非空目录的移动操作会依赖操作系统的支持。在 UNIX 系统中,如果目录在同一分区内进行移动,实际上是通过重命名来实现的,甚至包含子文件的目录也能被移动。
Path sourceDir = Paths.get("/home/user/dir");
Path targetDir = Paths.get("/home/user/dir_backup");
Files.move(sourceDir, targetDir, REPLACE_EXISTING);

示例:使用ATOMIC_MOVE保证原子操作

import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;

public class FileMoveDemo {
    public static void main(String[] args) {
        Path source = Paths.get("example.txt");
        Path target = Paths.get("backup/example.txt");

        try {
            Files.move(source, target, REPLACE_EXISTING, ATOMIC_MOVE);
            System.out.println("✅ 文件成功移动!");

        } catch (IOException e) {
            System.err.println("❌ 文件移动失败:" + e.getMessage());
        }
    }
}

这里的 ATOMIC_MOVE 保证了文件在移动过程中不会被其他进程看到半成品。如果操作系统或文件系统不支持原子操作,会抛出异常。

4. 使用 Varargs 传递多个选项

你可以传入多个 CopyOption 枚举值来定制操作。例如:

Files.move(source, target, REPLACE_EXISTING, ATOMIC_MOVE);

这会执行一个替换目标文件且确保原子性的移动操作。

5. 错误处理

如果目标路径已存在并且你没有使用 REPLACE_EXISTINGmove() 会抛出 FileAlreadyExistsException。如果操作系统不支持原子操作(尤其是 ATOMIC_MOVE),会抛出 IOException

try {
    Files.move(sourcePath, targetPath, REPLACE_EXISTING);
} catch (FileAlreadyExistsException e) {
    System.err.println("❌ 目标文件已存在,未能移动!");
} catch (IOException e) {
    System.err.println("❌ 文件移动失败:" + e.getMessage());
}

6. 原子操作(Atomic Operations)

原子操作意味着整个操作要么完成,要么完全失败。对于多进程环境中的文件操作,原子操作非常关键。举个例子,如果你在复制文件时发生了中断,原子操作可以保证文件要么完全复制,要么根本不进行任何复制操作,避免部分完成的状态。

小结

操作类别方法
文件/目录移动Files.move(Path, Path, ...)
移动选项REPLACE_EXISTING, ATOMIC_MOVE

Java IO API - 复制文件和目录

在日常开发中,复制文件或目录是非常常见的需求。Java 提供了灵活且强大的 Files.copy() 方法来处理这些操作。

1. 基本用法

Files.copy(sourcePath, targetPath);

这行代码会尝试将 sourcePath 复制到 targetPath,但如果目标已存在,会抛出 FileAlreadyExistsException

2. 常用复制选项(CopyOption)

你可以使用可变参数(varargs)形式传入多个选项:

Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
枚举常量含义说明
REPLACE_EXISTING如果目标已存在则替换。对于符号链接,会复制“链接本身”,而非其指向目标。
COPY_ATTRIBUTES尽量复制原文件的属性(如修改时间等)。平台支持情况可能不同。
NOFOLLOW_LINKS如果源是符号链接,仅复制链接本身,而不跟踪其目标。

3. 注意:目录复制不包含内容!

虽然你可以复制一个目录:

Files.copy(Paths.get("docs"), Paths.get("docs_copy"));

但是这样复制的是空目录,原始目录中的子文件和子目录不会自动复制

如果你想复制整个目录结构,需要使用递归或第三方库(如 Apache Commons IO)。

4. 关于符号链接的行为

默认情况下,复制符号链接会复制它所指向的目标内容:

Files.copy(linkPath, copyPath); // 默认会“追踪”链接并复制目标

但如果你只想复制“链接本身”:

Files.copy(linkPath, copyPath, NOFOLLOW_LINKS);

示例:完整文件复制流程

import java.nio.file.*;
import java.io.IOException;
import static java.nio.file.StandardCopyOption.*;

public class FileCopyDemo {
    public static void main(String[] args) {
        Path source = Paths.get("example.txt");
        Path target = Paths.get("backup/example.txt");

        try {
            Files.copy(source, target, REPLACE_EXISTING, COPY_ATTRIBUTES);
            System.out.println("✅ 文件复制成功!");
        } catch (IOException e) {
            System.err.println("❌ 复制失败:" + e.getMessage());
        }
    }
}

5. 从流中复制 / 到流中复制

除了 Path-to-Path 的复制,Files 类还支持以下操作:

InputStream → File

try (InputStream in = new FileInputStream("source.txt")) {
    Files.copy(in, Paths.get("target.txt"), REPLACE_EXISTING);
}

File → OutputStream

try (OutputStream out = new FileOutputStream("output.txt")) {
    Files.copy(Paths.get("source.txt"), out);
}

适用于文件上传、下载等场景!

常见错误与建议

问题场景建议或说明
目标文件存在导致异常使用 REPLACE_EXISTING
复制目录却发现是空的递归复制子文件或使用第三方库
权限不足导致 IOException检查文件读写权限
想保留时间戳等属性但没生效尽量使用 COPY_ATTRIBUTES,并测试平台兼容性

小结

操作类别方法
文件复制Files.copy(Path, Path, ...)
输入流 → 文件复制Files.copy(InputStream, Path)
文件 → 输出流复制Files.copy(Path, OutputStream)

Java IO API - 删除文件和目录

在文件操作中,删除是一个非常常见但需要小心处理的操作,尤其在涉及目录和符号链接时更是如此。

1. 删除的基本规则

  • 文件(file):可以直接删除。
  • 目录(directory):必须为空,否则删除会失败。
  • 符号链接(symbolic link):删除的是链接本身,不是它指向的目标。

2. 删除文件的两种方式

Java 提供了两种方式来删除文件或目录:

方法一:Files.delete(Path path)

此方法用于强制删除,如果删除失败会抛出异常,适合你希望清楚了解失败原因的场景。

示例代码:

try {
    Files.delete(Paths.get("data.txt"));
    System.out.println("✅ 文件删除成功!");
} catch (NoSuchFileException e) {
    System.err.println("❌ 文件不存在:" + e.getMessage());
} catch (DirectoryNotEmptyException e) {
    System.err.println("📂 目录不为空,无法删除:" + e.getMessage());
} catch (IOException e) {
    System.err.println("⚠️ 删除失败,可能是权限问题:" + e.getMessage());
}

方法二:Files.deleteIfExists(Path path)

此方法删除文件,但如果文件不存在也不会抛出异常,返回值为 true 表示删除成功,false 表示文件本来就不存在。

示例代码:

Path path = Paths.get("temp.log");

try {
    boolean deleted = Files.deleteIfExists(path);
    if (deleted) {
        System.out.println("✅ 文件已删除");
    } else {
        System.out.println("ℹ️ 文件原本就不存在");
    }
} catch (IOException e) {
    System.err.println("⚠️ 删除失败:" + e.getMessage());
}

应用场景建议

场景建议方法
你希望严格处理删除失败并报告原因Files.delete(path)
你只是想安静地尝试删除,不管是否存在Files.deleteIfExists(path)
多线程环境,避免竞争删除时抛异常deleteIfExists 更合适

补充提示:递归删除目录

标准 API 没有提供递归删除目录的方法,如果你想要删除非空目录,需要自己遍历子文件并逐个删除。例如:

void deleteRecursively(Path path) throws IOException {
    if (Files.isDirectory(path)) {
        try (DirectoryStream<Path> entries = Files.newDirectoryStream(path)) {
            for (Path entry : entries) {
                deleteRecursively(entry);
            }
        }
    }
    Files.delete(path);
}

安全注意事项

  • 删除操作不可恢复,请务必确认路径。
  • 删除目录前应检查是否为空,或考虑是否应该递归删除。
  • 文件可能正在被其他进程使用,导致删除失败。
  • 有些系统目录(如 Windows 的 C:\Windows)根本不允许删除,尝试会抛异常。

总结小表

方法行为是否抛出异常
Files.delete(path)删除文件/空目录是(失败即抛)
Files.deleteIfExists()删除,文件不存在也不报错是(但文件不存在不抛)
递归删除目录自定义实现遍历目录后逐个删除是(建议封装)

到此这篇关于Java IO API实现文件和目录移动、复制和删除操作的文章就介绍到这了,更多相关Java文件和目录操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IDEA插件之彩虹括号Rainbow Brackets使用介绍

    IDEA插件之彩虹括号Rainbow Brackets使用介绍

    这篇文章主要为大家介绍了IDEA插件之彩虹括号Rainbow Brackets使用介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • SpringBoot整合阿里云开通短信服务详解

    SpringBoot整合阿里云开通短信服务详解

    这篇文章主要介绍了如何利用SpringBoot整合阿里云实现短信服务的开通,文中的示例代码讲解详细,对我们学习有一定帮助,需要的可以参考一下
    2022-03-03
  • java开发分布式服务框架Dubbo原理机制详解

    java开发分布式服务框架Dubbo原理机制详解

    这篇文章主要为大家介绍了java开发分布式服务框架Dubbo的原理机制详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • 关于Filter中获取请求体body后再次读取的问题

    关于Filter中获取请求体body后再次读取的问题

    这篇文章主要介绍了关于Filter中获取请求体body后再次读取的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Spring @Scheduled的坑及解决

    Spring @Scheduled的坑及解决

    这篇文章主要介绍了Spring @Scheduled的坑及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Spring实现HikariCP连接池的示例代码

    Spring实现HikariCP连接池的示例代码

    在SpringBoot 2.0中,我们使用默认连接池是HikariCP,本文讲一下HikariCP的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2021-08-08
  • 简单讲解java中throws与throw的区别

    简单讲解java中throws与throw的区别

    这篇文章主要介绍了简单讲解java中throws与throw的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • idea.vmoptions 最佳配置方案

    idea.vmoptions 最佳配置方案

    本文介绍了针对IntelliJ IDEA的优化配置建议,包括提升内存设置、启用G1垃圾回收器、优化垃圾回收策略以及调整网络设置等,旨在提高IDE的性能和响应速度,同时,指导用户如何修改vmoptions文件以应用这些配置,并提供了监控内存使用和插件管理的建议
    2024-09-09
  • 一次因Java应用造成CPU过高的排查实践过程

    一次因Java应用造成CPU过高的排查实践过程

    一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环。下面这篇文章主要给大家介绍了一次因Java应用造成CPU过高的排查实践过程,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-11-11
  • Java基础之颜色工具类(超详细注释)

    Java基础之颜色工具类(超详细注释)

    这篇文章主要介绍了Java基础之颜色工具类(超详细注释),文中有非常详细的代码示例,对正在学习java基础的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04

最新评论