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

我提出的其他想法是:

  • 解析传入的XML文件并测试关闭标签是否存在。
  • 检查 EoF 字符。

我只是不确定这些方法是否能够处理所有场景。

有帮助吗?

解决方案

不,canWrite 不适合此用途。一般来说,即使另一个进程正在写入,文件也将是可写的。

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

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

由于在本例中您只使用 XML,因此寻找关闭标记是可行的,但这并不是万无一失的 — 如果最终标记后有注释,或者编写者根本没有编写有效的 XML,该怎么办?

寻找 EOF 将 不是 工作。即使编写者刚刚打开文件并且尚未写入任何内容,也总会有 EOF。如果不是这样,最简单的事情就是让读者在文件出现后立即开始解析;它只会阻塞,直到作者关闭文件。但文件系统不是这样工作的。每个文件都有一个结尾,即使某些进程当前正在移动它。

其他提示

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

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

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

在Windows中似乎有效的一件事是 - 创建一个代表所讨论的文件(使用带有完整文件名的构造函数)的File()对象 - 创建第二个相同的文件对象。- 尝试firstFile.renameTo(secondFile)

对于未打开以供其他应用程序编辑的文件(我使用 Word 进行了测试),此虚拟重命名练习似乎会成功,但如果它们已打开,则会失败。

由于 nw 文件名 = 旧文件名,它不会创建任何其他工作。

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

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top