可能是一个简单的答案,但是我尝试阅读StandardOpenOption上的javadoc文档,但是我仍然不清楚当我说

Files.write(..., ..., StandardOpenOption.WRITE, StandardOpenOption.CREATE); // Write A

根据一些本地测试,看起来如果文件已经存在,它将仍然覆盖该文件,因此上述文件和文件之间有什么区别

Files.write(..., ..., StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); // Write B

此外,我有一个具有两个线程的程序,可以从写入的文件中进行读取/写入。当我使用Write B时,有时会遇到竞争情况,其中一个线程会创建文件,而另一个线程在第一个线程正在读取时会覆盖该文件,并且会出现异常。但是,当我使用Write A时,我永远不会遇到这种竞争情况。几乎好像会先锁定文件?有人可以解释幕后发生的事情吗?

最佳答案

当使用StandardOpenOption.TRUNCATE_EXISTING时,如果文件在写之前已经存在,则文件的长度首先被“截断为0”:

$ jshell

jshell> import java.nio.file.*;

jshell> Path path = Paths.get("foo");
path ==> foo

jshell> Files.write(path, "AAAA".getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE)


我刚刚创建了一个名为“ foo”的新文件,其中包含字符串“ AAAA”:

$ more foo
AAAA
$


现在,我将字符串“ BB”写入没有StandardOpenOption.TRUNCATE_EXISTING选项的文件中:

jshell> Files.write(path, "BB".getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE)


并且仅前两个字符被覆盖,其他字符仍然存在:

$ more foo
BBAA
$


现在,我再次写入字符串“ BB”,但添加了StandardOpenOption.TRUNCATE_EXISTING选项:

jshell> Files.write(path, "BB".getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)


该文件仅包含“ BB”,因为在编写之前,该文件的先前内容已被StandardOpenOption.TRUNCATE_EXISTING擦除:

$ more foo
BB
$

10-08 10:58