【问题标题】:Check if file written by process A is ready to be read by process B检查进程 A 写入的文件是否准备好被进程 B 读取
【发布时间】:2015-05-27 05:55:23
【问题描述】:

我有一个执行 k-shell 的 Java 脚本,该脚本调用一个写入文件 A 的程序。此后,相同的 Java 脚本解析输出文件 A。没有其他进程读取或写入文件 A。

问题是文件 A 并不总是准备好及时解析,我认为这是因为即使在程序和调用 shell 返回之后文件系统仍在完成其工作。这仅在有大量进程正在运行时才会发生。

lsof 似乎无法在我的系统上运行。如果我用编辑器打开一个文件,lsof 会显示编辑器进程,但如果我将文件名传递给 lsof,我会得到: lsof: 没有找到文件使用:文件名

我认为 fileLock 不会起作用,因为我必须在从程序或 k-shell 返回之前解锁它,到那时文件可能还没有完全关闭。

我的想法是编写一个简短的脚本来重命名(mv)文件,然后让解析器解析重命名的文件,我的理解是文件在完全写入之前无法重命名。我把 mv 命令放在一个 while 循环中,检查 mv 命令的 stdOut 中是否有任何内容,理论上如果它是空的,我们就可以开始了。

#! /bin/ksh
# Move a file. The idea is that this script will not return until the mv is
# complete. If mv is successful, mv.out.txt should be empty.

mv $1/camber.out $1/camber.out.copy > mv.out.txt
while [[ -s mv.out.txt ]] ; 
do
    echo "mv did not happen"
    mv $1/camber.out $1/camber.out.rename > mv.out.txt
done
echo "mv should have taken place"

exit

我还没有看到举起 mv 的实例。任何 cmets、建议、提示或侮辱将不胜感激。在此先感谢大家。

【问题讨论】:

  • 文件应该在mv返回后可用,无论是重命名还是cp。其次,我认为你误解了一些事情。 “mv a b > c”表示“将 a 移动到 b,将 mv 的所有输出重定向到名为 c 的文件”。 mv 通常不打印任何内容,因此该文件将为空。 -s 测试检查文件是否存在,并且大小大于 0。这意味着“如果第一个 mv 确实说了什么,请尝试将原始文件移动到 .rename ,并再次检查 mv 输出”。跨度>
  • 另外,您是尝试从 JavaScript 还是从 Java 执行此操作?请粘贴您目前拥有的代码。
  • @folkol 我正在使用供应商的包,它通过自己的方法实现系统调用: public void run(java.lang.String cmd) throws java.lang.Exception 运行命令。在子进程完成之前,此函数不会返回。在我的代码中,“cmd”将是运行运行程序的 k-shell 和上面的重命名脚本的命令。我的代码将使用 JavaScript。抱歉,我无法全部粘贴...
  • @folkol 我刚刚对上面的代码进行了一些调整,使用“2> mv.out.txt”重定向到 stdErr。我做了一个小测试,故意将第一个“mv”中的from fileName更改为不存在的东西,并且我在mv.out.txt中得到了一些东西,所以这部分似乎可以工作。
  • 你真的在运行 JavaScript 吗?如果您正在运行 Java,请参阅下面 Tomboyo 的回答。

标签: javascript linux shell wait lsof


【解决方案1】:

我缺乏评论的能力,所以应该是这样的答案。无论如何,这听起来像是异步执行的问题-java程序调用bash脚本,该脚本由操作系统作为单独的程序处理,因此与java程序同时运行。为了让一切正常运行,您只需要确保 bash 脚本同步运行 - 也就是说,脚本必须在 Java 继续之前完成。我相信this SO 与阻止相关的答案应该做你需要的。解决办法是这样的:

ProcessBuilder pb = new ProcessBuilder("myscript.sh");
Process p = pb.start();     // Start the process.
p.waitFor();                // Wait for the process to finish.
System.out.println("Script executed successfully");

这应该会强制 Java 程序休眠,直到 bash 脚本完成。

正如您在下面的评论中指出的那样,可能需要对 k-shell 应用相同的逻辑。您可以使用wait 命令,它将作业作为可选参数来等待进程(如果您不传入特定作业,则该进程将等待所有子进程完成)。

【讨论】:

  • 谢谢你!我相信你是对的,除了我担心程序在写入实际完成之前将控制权返回给 KSH。所以即使脚本完成了,程序的写入也可能不会。问题是,我真的不知道......
  • 你是对的。您应该能够在 ksh 中执行类似的操作。更新的答案也反映了这一点。如果需要,请查看 computerhope.com/unix/uksh.htm 以了解有关等待命令的详细信息以及识别作业的方法。
  • JavaScript 可以访问 Java 方法。我正在使用的包装程序包有一个系统调用方法,它可以执行您所描述的操作,所以这就是答案。显然,我们正在使用的文件系统在真正受到重创时会出现一些异步问题(就像我们正在做的那样)。我已经实现了等待命令,到目前为止我们还可以,虽然由于故障很少见,我没有绝对的答案。感谢tomboyo和folkol!你太棒了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 2021-02-10
相关资源
最近更新 更多