我有一个Java应用程序,它监视传入XML文件的文件夹。检测到新文件时,我需要测试当前未更新并关闭的文件。我的想法是使用File.canWrite()来测试这个。这样做有什么问题吗?这是测试文件是否已完全写入的好方法吗?
我要抛弃的其他想法是:
我不确定这些方法中的任何一种都能处理所有情况。
答案 0 :(得分:14)
不,canWrite不适用于此目的。通常,即使另一个进程正在编写,该文件也是可写的。
您需要更高级别的协议来协调锁定。如果您打算在单个平台上使用此代码,则可以使用NIO's FileLock facility。但请仔细阅读文档,并注意在许多平台上,锁只是建议性的。
另一种方法是让一个进程使用您的进程无法识别的名称写入文件,然后在写入完成时将文件重命名为可识别的名称。在大多数平台上,如果源和目标是相同的文件系统卷,则重命名操作是原子操作。名称更改可能使用不同的文件扩展名,甚至可以将文件从一个目录移动到另一个目录(在同一卷上)。
因为在这种情况下你只使用XML,所以查找close标签会起作用,但它并不是万无一失的 - 如果在最终标记之后有注释,或者编写器或者根本没有编写有效的XML ?
寻找EOF将不工作。即使作者刚刚打开文件并且还没有写入任何内容,总会有EOF。如果不是这样,那么最容易让读者在文件出现后立即开始解析;它会直接阻止,直到作者关闭文件。但是文件系统不能以这种方式工作。即使某个进程正在移动它,每个文件都有一个结束。
答案 1 :(得分:4)
此外,如果您执行检查后写入,那么您将遇到竞争条件。状态可以在检查和写入之间改变。有时最好尝试做你想要的事情并优雅地处理错误。也许是一种n次尝试重试机制,具有增加的回退延迟时间。
或重新定义您的测试。在这种情况下,您可以测试文件大小在处理之前的一段时间内没有发生变化。
另一种选择是将代码分成两部分,你可以有另一个线程 - 也许是一个石英任务 - 负责将完成的文件移动到主代码处理的不同目录中。
答案 2 :(得分:2)
在Windows中似乎有用的一件事是这样的 - 创建一个表示相关文件的File()对象(使用带有完整文件名的构造函数) - 以相同的方式创建第二个相同的文件对象。 - 尝试firstFile.renameTo(secondFile)
这个虚拟重命名练习似乎是成功的文件没有打开供另一个应用程序编辑(我用Word测试),但如果它们是打开的则会失败。
由于nw filename =旧文件名,因此不会创建任何其他工作。
答案 3 :(得分:1)
据我所知,没有办法判断另一个进程当前是否具有Java文件的打开句柄。一种选择是使用新io中的FileLock类。并非所有平台都支持此功能,但如果文件是本地文件并且编写文件的进程合作,则这适用于任何支持锁的平台。
答案 4 :(得分:0)
如果你同时控制阅读器和编写器,那么潜在的锁定技术就是创建一个锁目录 - 这通常是一个原子操作 - 用于读取和写入过程的持续时间。如果采用这种方法,则必须管理进程的潜在故障,从而导致“挂起”锁定目录。
正如Cheekysoft所提到的,文件不是原子的,不适合锁定。
如果您不控制编写器 - 例如,如果它是由FTP守护程序生成的 - 则重命名技术或延迟时间跨度技术是您的最佳选择。