检查文件是否存在java.nio

问题描述

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

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检查文件/目录是否存在可能是什么问题和可能的解决方案?

解决方法

您做错了。

在受外部更改影响的环境(例如文件系统)中工作的一般原则,您不能进行检查并采取行动。在这样的环境中,整个原理都被破坏了,您正在这里进行操作:

您检查文件是否存在,然后根据结果选择一个操作。这是检查并操作,并且无效。

毕竟,如果支票的“答案”在支票和行为之间改变了怎么办?它甚至不必是您自己的VM中的另一个线程,而可以是另一个进程。您也无法同步任何事情以“安全”地完成这项工作。

不,正确的原则是先检查后再使用。原子地执行“仅在文件尚未存在时才制作此文件”操作,并处理掉后尘,即,如果文件已存在,则事后处理错误。

幸运的是,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.