简体   繁体   English

Java File方法“canWrite()”可以支持锁定吗?

[英]Can the Java File method “canWrite()” support locking?

I have a Java application that monitors a folder for incoming XML files. 我有一个Java应用程序,它监视传入XML文件的文件夹。 When a new file is detected I need to test the file that it is not currently being updated and is closed. 检测到新文件时,我需要测试当前未更新并关闭的文件。 My thought is to use File.canWrite() to test this. 我的想法是使用File.canWrite()来测试它。 Is there any issue with doing this? 这样做有什么问题吗? Is this a good way to test that a file has been completely written? 这是测试文件是否已完全写入的好方法吗?

Other ideas I am throwing around are: 我投掷的其他想法是:

  • Parse the incoming XML file and test that the closing tag is there. 解析传入的XML文件并测试结束标记是否存在。
  • Check for the EoF character. 检查EoF角色。

I just am not sure that any of these methods will handle all scenarios. 我只是不确定这些方法中的任何一种都能处理所有场景。

No, canWrite is not suitable for this purpose. 不,canWrite不适用于此目的。 In general the file will be writable even if another process is writing. 通常,即使另一个进程正在编写,该文件也是可写的。

You need a higher level protocol to coordinate the locking. 您需要更高级别的协议来协调锁定。 If you plan to use this code on a single platform, you may be able to use NIO's FileLock facility . 如果您计划在单个平台上使用此代码,则可以使用NIO的FileLock工具 But read the documentation carefully, and note that on many platforms, the lock is only advisory. 但请仔细阅读文档,并注意在许多平台上,锁只是建议性的。

Another approach is to have one process write the file with a name that your process won't recognize, then rename the file to a recognizable name when the write is complete. 另一种方法是让一个进程使用您的进程无法识别的名称写入文件,然后在写入完成时将文件重命名为可识别的名称。 On most platforms, the rename operation is atomic if the source and destination are the same file system volume. 在大多数平台上,如果源和目标是相同的文件系统卷,则重命名操作是原子操作。 The name change might use a different file extension, or even moving the file from one directory to another (on the same volume). 名称更改可能使用不同的文件扩展名,甚至可以将文件从一个目录移动到另一个目录(在同一卷上)。

Since in this case you are working exclusively with XML, looking for a close tag would work, but it isn't foolproof—what if there are comments after the final markup, or the writer or simply doesn't write valid XML? 因为在这种情况下你只使用XML,所以查找一个close标签是可行的,但它并不是万无一失的 - 如果在最终标记之后有注释,或者编写器还是根本没有编写有效的XML?

Looking for the EOF will not work. 寻找EOF将无法正常工作。 There will always be an EOF, even when the writer has just opened the file and hasn't written anything yet. 即使作者刚刚打开文件并且还没有写入任何内容,总会有EOF。 If this weren't so, the easiest thing would be to allow the reader to start parsing as soon as the file showed up; 如果不是这样,那么最容易让读者在文件出现后立即开始解析; it would simply block until the writer closed the file. 它会直接阻止,直到作者关闭文件。 But the file system doesn't work this way. 但是文件系统不能以这种方式工作。 Every file has an end, even if some process is currently moving it. 即使某个进程正在移动它,每个文件都有结束。

Additionally, if you do a check followed by a write, then you have a race condition. 此外,如果您进行检查后写入,那么您就有竞争条件。 The state could change between the check and the write. 状态可以在检查和写入之间改变。 Sometimes its best to try and do the thing you want and handle errors gracefully. 有时最好尝试做你想要的事情并优雅地处理错误。 perhaps an n-attempt retry mechanism with a increased fallback delay time. 也许是一种具有增加的回退延迟时间的n次尝试重试机制。

Or redefine your test. 或者重新定义您的测试。 In this case, you could perhaps test that the filesize hasn't changed over a period of time before processing it. 在这种情况下,您可以测试文件大小在处理之前的一段时间内没有发生变化。

Another option is to split the code into two, you could have another thread -- perhaps a quartz task -- responsible for moving finished files into a different directory that your main code processes. 另一种选择是将代码分成两部分,你可以有另一个线程 - 也许是一个石英任务 - 负责将完成的文件移动到主代码处理的不同目录中。

One thing that appears to work in Windows is this - Create a File() object that represents the file in question (using constructor with full filename) - Create a second identical File Object, same way. 在Windows中似乎有用的一件事是 - 创建一个表示相关文件的File()对象(使用带有完整文件名的构造函数) - 以相同的方式创建第二个相同的文件对象。 - Try firstFile.renameTo(secondFile) - 尝试firstFile.renameTo(secondFile)

This dummy renaming exercise seems to succeed with files that are not open for editing by another app (I tested with Word), but fails if they are open. 这个虚拟重命名练习似乎是成功的文件没有打开供另一个应用程序编辑(我用Word测试),但如果它们是打开的则会失败。

And as the nw filename = the old filename it doesn't create any other work. 由于nw filename =旧文件名,因此不会创建任何其他工作。

As far as I know, there is no way to tell if another process currently has an open handle to a file from Java. 据我所知,没有办法判断另一个进程当前是否具有Java文件的开放句柄。 One option is to use the FileLock class from new io. 一种选择是使用new io中的FileLock类。 This isn't supported on all platforms, but if the files are local and the process writing the file cooperates, this should work for any platform supporting locks. 并非所有平台都支持此功能,但如果文件是本地文件并且编写文件的进程是合作的,则这适用于任何支持锁的平台。

If you control both the reader and writer, then a potential locking technique would be to create a lock directory -- which is typically an atomic operation -- for the read and the write process duration. 如果你同时控制读写器,那么潜在的锁定技术就是创建一个锁定目录 - 这通常是一个原子操作 - 用于读取和写入过程的持续时间。 If you take this type of approach, you have to manage the potential failure of a process resulting in a "hanging" lock directory. 如果采用这种方法,则必须管理进程的潜在故障,从而导致“挂起”锁定目录。

As Cheekysoft mentioned, files are not atomic and are ill suited for locking. 正如Cheekysoft所提到的,文件不是原子的,不适合锁定。

If you don't control the writer -- for instance if it's being produced by an FTP daemon -- then the rename technique or delay for time span technique are your best options. 如果您不控制编写器 - 例如,如果它是由FTP守护程序生成的 - 则重命名技术或延迟时间跨度技术是您的最佳选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM