【问题标题】:Check does file exist java.nio检查文件是否存在 java.nio
【发布时间】:2020-10-06 20:18:58
【问题描述】:

我正在尝试检查文件是否存在,但它不起作用。

FileSystem fs = FileSystems.getDefault();
Path p = fs.getPath(fileName);

if(!Files.exists(p)) {
    create(fileName);
} else {
    throw new ConflictException(String.format("File already exist."));
}

问题是即使文件存在相同的文件名,它也会进入if statement 并转到create 方法,当它开始创建文件时,它会返回文件已经存在的异常。 如果我使用 FileSystem,检查文件/目录是否存在可能是什么问题和可能的解决方案?

【问题讨论】:

    标签: java filesystems java.nio.file


    【解决方案1】:

    你做错了。

    在受外部变化影响的环境(例如文件系统)中工作时的一般原则,您只是不能进行检查和操作。在这样的环境中,整个原则都被打破了,而你正在这样做:

    您检查文件是否存在,然后根据结果选择一个操作。那是check-and-act,不起作用。

    毕竟,如果支票的“答案”在支票和行为之间发生变化怎么办?它甚至不必是您自己的虚拟机中的另一个线程,它可以是另一个进程。你也不能同步任何东西来“安全地”完成这项工作。

    不,正确的原则是act-then-check。以原子方式执行“制作此文件,但仅当它不存在时”操作,并处理后果,即,如果文件已存在,则事后处理错误。

    幸运的是,Java 的 nio 支持这一点(旧的 File API 不支持,不要使用它)。最后,只要您使用默认文件系统,就不需要通过 FileSystem 的东西。但是,如果这只是为了简化问题,那么它同样适用于自定义文件系统:

    Path p = Paths.get(fileName);
    
    try {
        try (var out = Files.newOutputStream(p, StandardOpenOption.CREATE_NEW)) {
           // write your file here
        }
    } catch (FileAlreadyExistsException e) {
        throw new ConflictException(String.format("File already exists", e);
    }
    // CREATE_NEW is the magic voodoo here: That tells java:
    // do this ONLY if you make a new file, otherwise don't do it, atomically.
    

    虽然请注意 FAEException 是正常的,所以我不确定你是否应该将它包装成一个冲突异常 - 只有当这个 API 已经抽象出你正在对文件系统做这件事的概念时才有意义(你您的粘贴中没有包含方法名称或 javadoc,所以我不知道)。

    如果您不需要向文件中写入任何内容,则不需要newOutputStream,您可以使用:

    Path p = Paths.get(fileName);
    
    try {
        Files.createFile(p);
    } catch (FileAlreadyExistsException e) {
        throw new ConflictException(String.format("File already exists", e);
    }
    // Files.createFile implies CREATE_NEW already; it either makes
    // the file and returns, or doesn't and throws FAEEx.
    

    【讨论】:

    • 我们是否知道其他进程可能正在创建文件?如果只是 kavkax 的程序创建它们,那么原子检查将无法解决问题。
    • @VGR ...但它会解决问题。 check-then-act 在情况 A 中运行良好,在情况 B 中失败。 act-then-check 在 A 中运行良好,在 B 中运行良好,这使得它非常优越。 (A = 没有其他进程干扰文件系统并且没有其他线程,B = 有其他进程和/或线程可以创建该文件)。
    • 对于上下文,听起来 kavkax 的问题可能与例如更相关。首先有错误的文件名。然而,帮助某人调试根本无法完成预期工作的代码并没有什么意义。最好首先至少设置它,以便它至少可以完成它应该做的工作,然后如果重写后仍然存在问题,请修复它们。
    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 2021-07-22
    • 2013-07-17
    • 2012-12-23
    相关资源
    最近更新 更多