锁定未来文件

时间:2013-12-09 21:32:48

标签: java file locking file-locking

所以我有一个Samba文件服务器,我的Java应用程序需要在其上编写一些文件。问题是还有另一个php应用程序(如果一个php脚本甚至被认为是一个应用程序)正在积极地为新文件拉相同的目录。

有时,php脚本在我的Java应用程序完成将其完全写入磁盘之前拉动文件。这是一些ascii艺术,以帮助可视化我目前拥有的(但不起作用):

Samba分享

/foo(我的java应用程序在此处删除文件)

/bar(php正在拉动的目录)

我目前正在做的是当文件符合某些标准时,它会被移动到/bar,然后由php获取以进行更多处理。我尝试过不同的事情,例如在调用renameTo之前将文件设置为不可写且不可读。

我在FileLock看了一下,但它似乎无法锁定未来的文件。所以我想知道我在这里有什么样的可能性?我可以使用什么来锁定文件,使其在完全编写之前没有触及php(因为,好吧,它是php,我现在没有权利修改它)。

由于

修改1

如果它可以以任何方式提供帮助,我对php脚本的实际操作有了一些了解。

它正在循环中读取目录文件(使用readdir而不休眠)。

一旦找到“。”以外的文件名。和“..”,它调用file_get_contents,这就是它失败的原因,因为文件没有完全写入磁盘(或者甚至没有,因为Java代码甚至没有时间在{{1}之间写入它}和readdir

修改2

这个Java应用程序正在取代旧的PHP脚本。当他们实施它时,他们遇到了我现在遇到的同样问题。他们通过在file_get_contents中编写新文件(使用/bar/tmp)解决了这个问题,然后使用rename将其移动到bar(看起来重命名应该是原子的)。到目前为止它一直很好用。我不能也不会相信Java不能比php做得更好......

2 个答案:

答案 0 :(得分:0)

我认为这是因为读锁是共享的(多个进程可以将读锁应用于同一个文件并一起读取)。

您可以执行的一种方法是创建单独的临时锁定文件(例如:/bar/file1.lock),而/bar/file1尚未完成复制。文件复制完成后立即删除锁定文件。

然后改变php代码以确保文件在读取之前没有被锁定。

答案 1 :(得分:0)

您提到您尝试了FileLock,但请记住该方法的javadoc中的免责声明:

  

锁是否实际阻止其他程序访问   锁定区域的内容是系统相关的   不确定的。某些系统的本机文件锁定功能是   只是建议,意味着程序必须合作观察   已知的锁定协议,以保证数据的完整性。

您还提到您正在使用File.renameTo,这也有一些警告(在javadoc中提到):

  

此方法行为的许多方面都是固有的   依赖于平台:重命名操作可能无法移动   从一个文件系统到另一个文件系统的文件,它可能不是原子的,它   可能不会成功

而不是File.renameTo,请使用ATOMIC_MOVE选项尝试Files.move。如果无法进行原子移动,您必须抓住AtomicMoveNotSupportedException并可能退回到某些替代解决方法。

您可以使用Files.createLink(Paths.get('/foo/myFile'), 'Paths.get('/bar/myFile'))创建硬链接,然后删除原始目录条目(在此示例中为/foo/myFile

如果不这样做,一个不需要修改PHP的简单解决方法是使用shell命令或系统调用将文件从/ foo移动到/ bar。例如,您可以使用ProcessBuilder来调用mv,或者调用ln来在/ bar中创建符号链接或硬链接。如果/ foo和/ bar在不同的文件系统上,则mv可能仍然存在同样的问题。

如果您在服务器上拥有root权限,则还可以尝试实施强制文件锁定。我在C中找到了example,但您可以从Java调用C程序,或者使用JNA(或JNI,如果您想惩罚自己)将示例调整为Java。