进程分叉时的 Java 文件管理
我的猜测是错误的,与答案无关。这个问题不再有效。请参阅我的回答。对于这个糟糕的问题,我深表歉意。
Tl;dr 版本
为什么 Java 进程无法找到某个文件,直到另一个进程(创建该文件的进程)完成执行。这可以解决吗?
较长版本
我有一个应用程序需要自行重新启动(它只需要重新启动,好吗?)。第一次,它创建一个文件,然后在那里序列化一个对象。这是通过 FileOutputStream
/ObjectOutputStream
组合完成的,如下所述:
private static File serializeBootstrapInfoIntoFile(
final BootstrapInfo info) throws IOException {
final File tempFile = File.createTempFile("BobBootstrapInfo", null);
final FileOutputStream fos = new FileOutputStream(tempFile);
final ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(info);
// just being thorough
oos.flush();
oos.close();
fos.flush();
fos.close();
return tempFile;
}
在此之后,我使用 System.exec()
创建另一个 java 进程-call,我将返回的 tempFile 的绝对路径作为系统属性传递给该调用。然后,另一个 java 进程应该打开该文件,并反序列化包含的对象。第一个进程保持活动状态,直到生成的进程退出,因为它处理新进程的输出/错误流。
然而,问题是,第二个进程似乎找不到该文件,并且在反序列化期间总是在 FileNotFoundException 中终止(我已使用 file.exists() 确认了这一点) )。
后来手动检查,发现该文件确实存在。另外,如果我手动运行传递给 System.exec() 的完全相同的命令行,它运行得很好。因此,我猜测第一个进程以某种方式设法从新进程中隐藏文件,或者无法实际将文件写入文件系统,即使流被刷新并关闭。我还尝试在第一个线程上使用 Thread.sleep(10000) 来完成 IO 操作,但这没有一点帮助。
我做错了什么吗?或者这是 Java 的事情,或者可能是 OSX 的事情(我正在使用 atm 运行)?
评论的答复
我正在运行 OS X 10.6.3,Java 版本是 1.6.0_20。
System.exec()
参数中的
java
-classpath
/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/bob7168396245507677201.tmp:/Users/wolfie/Documents/workspace/Bob/dist/lib/junit.jar:/Users/wolfie/Documents/workspace/Bob/dist/lib/bob.jar
-Dcache.location="/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4944987280015634213.tmp"
com.github.wolfie.bob.Bob
每一行都是字符串数组中的一个元素。 /var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4606780571989099166.tmp 文件是已创建的文件,并由另一个线程读取。 envp
和 dir
参数为 null
。
整个堆栈跟踪是:
Exception in thread "main" com.github.wolfie.bob.BootstrapError: java.io.FileNotFoundException: "/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4606780571989099166.tmp" (No such file or directory)
at com.github.wolfie.bob.Bob.getBootstrapInfo(Bob.java:186)
at com.github.wolfie.bob.Bob.run(Bob.java:138)
at com.github.wolfie.bob.Bob.main(Bob.java:95)
Caused by: java.io.FileNotFoundException: "/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4606780571989099166.tmp" (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:106)
at com.github.wolfie.bob.Bob.deserializeBootstrapInfoFromFile(Bob.java:265)
at com.github.wolfie.bob.Bob.getBootstrapInfo(Bob.java:184)
... 2 more
My guesses were wrong, and had nothing to do with the answer. This question is no longer valid. See my answer. Sorry about this poor question.
Tl;dr Version
Why can't a Java process find a certain file, until another process – the process that created that file – has finished executing. Can this be worked around?
Longer Version
I have an application that needs to restart itself (it just needs to, okay?). The first time, it creates a File and then serializes an object there. This is done with a FileOutputStream
/ObjectOutputStream
combo, as described below:
private static File serializeBootstrapInfoIntoFile(
final BootstrapInfo info) throws IOException {
final File tempFile = File.createTempFile("BobBootstrapInfo", null);
final FileOutputStream fos = new FileOutputStream(tempFile);
final ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(info);
// just being thorough
oos.flush();
oos.close();
fos.flush();
fos.close();
return tempFile;
}
After this, I create another java process with a System.exec()
-call, to which I pass the the absolute path of the returned tempFile
as a system property. The other java process should then open the file, and deserialize the containing Object. The first process remains alive until the spawned process exits, since it handles the new one's output/error streams.
The problem is, however, that the second process doesn't seem to find the file, and dies always in a FileNotFoundException
during deserialization (I've confirmed this with a file.exists()
).
When I check manually afterwards, the file does indeed exist. Also, if I manually run the exact same command line that is passed to the System.exec()
, it runs fine. So, I'm guessing the first process somehow manages to hide the file from the new process, or fails to actually write the file to the file system, even the streams are flushed and closed. I also tried with Thread.sleep(10000)
on the first thread, to let the IO operations to finish, but that didn't help a bit.
Am I doing something wrong? Or is this a Java thing, or maybe an OSX thing (which I'm running with atm)?
Answers to Comments
I'm running OS X 10.6.3, and the Java version is 1.6.0_20.
The System.exec()
arguments are
java
-classpath
/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/bob7168396245507677201.tmp:/Users/wolfie/Documents/workspace/Bob/dist/lib/junit.jar:/Users/wolfie/Documents/workspace/Bob/dist/lib/bob.jar
-Dcache.location="/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4944987280015634213.tmp"
com.github.wolfie.bob.Bob
where each line is an element in a String array. The /var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4606780571989099166.tmp
-file is the one that was created, and being read by the other thread. The envp
and dir
arguments are null
.
The whole stacktrace is:
Exception in thread "main" com.github.wolfie.bob.BootstrapError: java.io.FileNotFoundException: "/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4606780571989099166.tmp" (No such file or directory)
at com.github.wolfie.bob.Bob.getBootstrapInfo(Bob.java:186)
at com.github.wolfie.bob.Bob.run(Bob.java:138)
at com.github.wolfie.bob.Bob.main(Bob.java:95)
Caused by: java.io.FileNotFoundException: "/var/folders/dr/drDlHsguGvq0zF2Jtgn4S++++TI/-Tmp-/BobBootstrapInfo4606780571989099166.tmp" (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:106)
at com.github.wolfie.bob.Bob.deserializeBootstrapInfoFromFile(Bob.java:265)
at com.github.wolfie.bob.Bob.getBootstrapInfo(Bob.java:184)
... 2 more
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从问题中看不到答案:我像这样定义了系统属性:
但该属性应该是相反的
,即没有引号。显然,当从命令行传递完全相同的参数时,这一点被忽略,可能是因为 Bash 以与 JVM 不同的方式处理它们。
很抱歉这个糟糕的问题。
The answer isn't visible from the question: I defined the system property like so:
But the property should've been instead
i.e. without the quotes. This, apparently, was ignored when the exact same arguments were passed from the command line, probably because Bash processed them in a different way to the JVM.
Sorry about the poor question.