12

我有一个 Java 应用程序,它监视传入 XML 文件的文件夹。当检测到新文件时,我需要测试该文件当前未更新并已关闭。我的想法是使用File.canWrite()来测试它。这样做有什么问题吗?这是测试文件是否已完全写入的好方法吗?

我抛出的其他想法是:

  • 解析传入的 XML 文件并测试结束标记是否存在。
  • 检查 EoF 字符。

我只是不确定这些方法中的任何一种都可以处理所有情况。

4

5 回答 5

14

不,canWrite 不适合此目的。通常,即使另一个进程正在写入,该文件也是可写的。

您需要更高级别的协议来协调锁定。如果您计划在单个平台上使用此代码,您可以使用NIO 的 FileLock 设施。但请仔细阅读文档,并注意在许多平台上,锁只是建议性的。

另一种方法是让一个进程使用您的进程无法识别的名称写入文件,然后在写入完成后将文件重命名为可识别的名称。在大多数平台上,如果源和目标是相同的文件系统卷,则重命名操作是原子操作。名称更改可能使用不同的文件扩展名,甚至将文件从一个目录移动到另一个目录(在同一卷上)。

由于在这种情况下您只使用 XML,因此寻找关闭标记会起作用,但它并非万无一失——如果在最终标记之后有注释,或者作者或根本没有编写有效的 XML,该怎么办?

寻找 EOF 是行不通的。总会有一个 EOF,即使作者刚刚打开文件并且还没有写任何东西。如果不是这样,最简单的方法是让读者在文件出现后立即开始解析;它只会阻塞,直到作者关闭文件。但是文件系统不能这样工作。每个文件都有一个结束,即使某个进程当前正在移动它。

于 2008-09-23T17:04:14.267 回答
4

此外,如果您先进行检查,然后再进行写入,那么您就会遇到竞争条件。状态可能会在检查和写入之间发生变化。有时最好尝试做你想做的事情并优雅地处理错误。可能是具有增加的回退延迟时间的 n 次尝试重试机制。

或者重新定义你的测试。在这种情况下,您也许可以在处理文件之前测试文件大小在一段时间内没有改变。

另一种选择是将代码分成两部分,你可以有另一个线程——也许是一个石英任务——负责将完成的文件移动到你的主代码处理的不同目录中。

于 2008-09-23T17:13:15.787 回答
2

在 Windows 中似乎可以工作的一件事是 - 创建一个表示相关文件的 File() 对象(使用具有完整文件名的构造函数) - 以相同的方式创建第二个相同的文件对象。- 尝试 firstFile.renameTo(secondFile)

这个虚拟重命名练习似乎成功地处理了未打开以供另一个应用程序编辑的文件(我用 Word 测试过),但如果它们打开则失败。

并且作为 nw 文件名 = 旧文件名,它不会创建任何其他工作。

于 2009-09-30T13:47:44.377 回答
1

据我所知,没有办法判断另一个进程当前是否具有来自 Java 的文件的打开句柄。一种选择是使用来自 new io的FileLock类。并非所有平台都支持此功能,但如果文件是本地文件并且写入文件的进程配合,则这应该适用于任何支持锁的平台。

于 2008-09-23T17:04:15.607 回答
0

如果您同时控制读取器和写入器,那么潜在的锁定技术将是创建一个锁定目录(通常是原子操作)以用于读取和写入过程持续时间。如果您采用这种方法,您必须管理导致“挂起”锁定目录的进程的潜在故障。

正如 Cheekysoft 提到的,文件不是原子的,不适合锁定。

如果您不控制编写器(例如,如果它是由 FTP 守护程序生成的),那么重命名技术或时间跨度延迟技术是您的最佳选择。

于 2008-09-23T17:52:13.713 回答