如何在Java中打开一个不阻止外部访问的文件;“安全保存”吗;?

如何在Java中打开一个不阻止外部访问的文件;“安全保存”吗;?,java,file,Java,File,我们想用Java打开一个文件并读取其内容 此文件可由外部应用程序使用安全保存进行更新。这意味着文件将从外部读取,其更新的内容将存储到新文件中。最终删除原始文件,并重命名新文件以匹配原始文件的名称 不幸的是,当Java应用程序同时读取原始文件时,重命名(安全保存的最后一部分)期间外部进程失败。 我们使用了不同的开放模式,但无法得到一个不会让外部阅读器失望的解决方案 是否有某种方法可以打开一个不干扰访问同一文件的外部进程的文件?理想情况下,每当外部进程移动或删除文件时,我们都希望Java应用程序中出

我们想用Java打开一个文件并读取其内容

此文件可由外部应用程序使用安全保存进行更新。这意味着文件将从外部读取,其更新的内容将存储到新文件中。最终删除原始文件,并重命名新文件以匹配原始文件的名称

不幸的是,当Java应用程序同时读取原始文件时,重命名(安全保存的最后一部分)期间外部进程失败。 我们使用了不同的开放模式,但无法得到一个不会让外部阅读器失望的解决方案

是否有某种方法可以打开一个不干扰访问同一文件的外部进程的文件?理想情况下,每当外部进程移动或删除文件时,我们都希望Java应用程序中出现异常。只有在那里

你对如何实现这一目标有什么想法吗

编辑:

只是一些关于用例的澄清:

这是一个类似索引器的场景。我们希望索引一个可能非常大的文件系统的内容,在这个文件系统中,独立于第三方的进程也可以并发地读写。我们无法控制第三方流程。 复制原始文件似乎是一个很大的开销,我们不确定这是否有助于解决原始问题,因为它也可能使外部读取器无法安全保存


最后但并非最不重要的一点:这应该适用于Windows和Linux。但是我们在Windows上遇到了这个问题。

制作原始文件的副本,并在Java程序中使用它,同时跟踪原始文件

在这里,这可能会帮助您:


file包提供了一个文件更改通知API,称为监视服务API。此API允许您向watch服务注册一个或多个目录。注册时,您会告诉服务您感兴趣的事件类型:文件创建、文件删除或文件修改。当服务检测到感兴趣的事件时,它被转发到已注册的进程。注册的进程有一个线程(或线程池),专门用于监视它注册的任何事件。当事件发生时,会根据需要进行处理

您不能仅通过文件来实现这一点,至少在不做额外假设的情况下是如此。如果进程不同步,您将获得(a)错误(b)损坏的数据或(c)两者。此外,此类系统将不稳定,容易受到竞争条件和具体实施细节的影响。这意味着,即使它看起来像是在工作,它也不会总是正确地工作

根据您的情况,您可能会尝试使用scehduling(即进程a每偶数分钟运行一次,进程B每奇数分钟运行一次)、独占/共享打开标志、范围锁、复制文件、文件更改通知、,如果你能以某种方式确保你的假设永远不会被打破,你可能会得到“足够好”的东西。但总而言之,这是一种糟糕的工程实践,应该避免


为了获得正确的解决方案,您需要让两个流程都知道它们正在相互交谈。您所拥有的实际上是一个数据库的教科书用例。除了使用数据库,还有很多其他方法可以同步数据访问—消息、流、锁、共享内存等。每种方法都有其优点和缺点,如果不了解您的具体情况,就无法确定哪种方法更好。

在Windows上,文件打开时是否可以重命名或删除由共享模式标志控制。当使用低级函数打开文件时,应传入此标志

不幸的是,JavaAPI不能让您控制低级别的Windows特定标志。默认情况下,存在添加文件共享删除的开放模式,但由于向后兼容性(某些应用程序可能依赖于此行为),不太可能这样做。报告中的A注释建议了一种解决方法:使用java.nio API代替
新文件输入流(file)

InputStream in = Files.newInputStream(file.toPath());

我现在没有访问Windows的权限,无法验证此解决方案是否使用了正确的共享模式。

Windows,这是在哪个操作系统上?我之所以这样问,是因为Unix上的正常行为允许您在文件打开时删除或重命名文件。所以我猜你一定是在Windows上,需要一个特定于Windows的solution@Joni你说得对。Windows上出现问题。谢谢您的回答。我编辑了我的问题。不幸的是,我们无法控制同时访问文件系统的第三方进程。谢谢您的回答。复制文件似乎是一个很大的开销,因为文件系统及其包含的文件可能会增加TB。此外,我们不确定这是否有助于解决原始问题,因为您也必须打开文件进行复制。这很可能也会导致外部删除/移动失败,不是吗?谢谢你的提示。实际上我们也试过这个。它确实允许在Java应用程序读取文件时删除文件。不幸的是,在后续的移动操作中,它仍然会使外部进程失败。