你做错了。
在受外部变化影响的环境(例如文件系统)中工作时的一般原则,您只是不能进行检查和操作。在这样的环境中,整个原则都被打破了,而你正在这样做:
您检查文件是否存在,然后根据结果选择一个操作。那是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.