【问题标题】:Lock future file锁定未来文件
【发布时间】:2013-12-09 21:32:47
【问题描述】:

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

有时,php 脚本会在我的 Java 应用程序完成将文件完全写入磁盘之前提取文件。这里有一点 ascii 艺术,可以帮助可视化我目前拥有的东西(但不起作用):

Samba 分享

/foo(我的 java 应用程序将文件放在这里)

/bar(php拉取的目录)

我目前正在做的是当文件满足某些条件时,它被移动到/bar,然后被 php 拾取以进行更多处理。我尝试了不同的方法,例如在调用 renameTo 之前将文件设置为不可写和不可读。

我看了一点FileLocks,但它似乎无法锁定未来的文件。所以我想知道我在这里有什么样的可能性?我可以用什么来锁定文件在它完全写入之前被拾取而不接触 php(因为,好吧,它是 php,我现在没有权利修改它)。

谢谢

编辑 1

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

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

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

编辑 2

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

【问题讨论】:

  • /foo 和 /bar 是否在同一个文件系统上?

标签: java file locking file-locking


【解决方案1】:

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

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

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

【讨论】:

  • 我也有同样的想法,但不幸的是,问题指出修改 PHP 不是一种选择。
【解决方案2】:

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

锁是否真正阻止其他程序访问 锁定区域的内容是系统相关的,因此 未指定。某些系统的本机文件锁定设施是 仅仅是建议性的,这意味着程序必须合作遵守 已知的锁定协议,以保证数据的完整性。

您还提到您正在使用File.renameTo,它也有一些注意事项(在 javadoc 中提到):

此方法的行为的许多方面都与生俱来 平台相关:重命名操作可能无法移动 文件从一个文件系统到另一个文件系统,它可能不是原子的,它 可能不会成功

试试Files.moveATOMIC_MOVE 选项,而不是File.renameTo。您必须抓住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。

【讨论】:

  • ATOMIC_MOVE 选项没有任何不同。在完全写入磁盘之前,文件仍在被拾取。我在 ProcessBuilder 中遇到奇怪的异常,说文件/路径不存在(错误 = 2),但是在控制台中粘贴确切的命令行可以......
  • 当您说在控制台中粘贴命令行有效时,您是说它执行了,还是说它也解决了 PHP 脚本拾取不完整文件的问题?请将您的 ProcessBuilder 代码和堆栈跟踪添加到问题中。
  • 它执行,到目前为止,它也解决了 php.ini 的问题。我会在这个问题上添加更多背景信息。
  • 您确定 Java 代码在您尝试移动文件之前完成了文件的写入(并调用了 close())吗?
  • 我假设是的。我正在使用FileUtils.copyFileToDirectory
猜你喜欢
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 2019-10-14
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 2015-04-14
相关资源
最近更新 更多