gpt4 book ai didi

java - 读取输出时如何处理 Java Processes 孙子?

转载 作者:行者123 更新时间:2023-11-30 07:45:40 25 4
gpt4 key购买 nike

在处理命令行的 JavaFX 模型时,我遇到了以下问题:
如果我运行一个运行另一个进程的进程(例如批处理文件)(例如使用简单的 start notepad 打开记事本)我似乎无法正确确定批处理文件何时完成执行:

  • Process#waitFor批处理文件启动时已经返回(我猜是因为我必须在可执行文件前面添加 cmd/c 并且 cmd 确实在几分之一秒后完成)
  • 使用 Process#getInputStream 读取输出仅在我关闭记事本后结束,而不是在批处理文件终止后结束。

有没有我一直想念的方法?更重要的是:如果有的话,如何确定通过 cmd/c 生成的进程的结束?

可重现的例子:

例子.bat:

@echo off
start notepad
REM You can change the path to something else but it should be something where tree produces a longer output to reproduce the problem.
cd %USERPROFILE%\Desktop
tree

Java代码:

import java.io.IOException;
import java.io.InputStream;

public class Main {

public static void main(String[] args) {
Process myProcess = null;
try {
myProcess = Runtime.getRuntime().exec("cmd /c C:\\Users\\geisterfurz007\\Desktop\\example.bat");
} catch (IOException e) {
e.printStackTrace();
}
startReadingThread(myProcess);

try {
myProcess.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Process ended");
}

private static void startReadingThread(Process myProcess) {
InputStream stream = myProcess.getInputStream();
new Thread(() -> {
int character;
try {
while ((character = stream.read()) != -1) {
System.out.write(character);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
System.out.println("Reading ended");
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}

}

开始打印树,中间打印“Process ended”被写入控制台。最后,在我关闭记事本窗口后打印“Reading ended”。
我的目标是找到树完成打印(即批处理文件完成处理)的点,忽略记事本关闭的时间。

基于 Leviands's answer我试图在它执行完后关闭 Processes 流,但无济于事。
不幸的是,InputStream 再次关闭中间内容,而 ErrorStream(我也在实际应用程序中读到)不会关闭,从而阻塞线程。

最佳答案

首先非常感谢Leviand谁提到了InputStream#available在他们的 answer这让我得到了一些看起来确实有效的东西:

想法是,在我正在寻找的时间点,Process#isAlive 应该返回 false,因为 Stream 的处理时间比 Process 进程长(如果这有意义的话),而 InputStream 应该没有可读的字符,所以 InputStream#available 应该返回 0。

这导致这段代码:

import java.io.IOException;
import java.io.InputStream;

public class Main {

public static void main(String[] args) {
Process myProcess = null;
try {
myProcess = Runtime.getRuntime().exec("cmd /c C:\\Users\\geisterfurz007\\Desktop\\example.bat");
} catch (IOException e) {
e.printStackTrace();
}
startReadingThread(myProcess).start();
}

private static Thread startReadingThread(Process myProcess) {
InputStream stream = myProcess.getInputStream();
return new Thread(() -> {
int character;
try {
while (myProcess.isAlive() || stream.available() > 0) {

if ((character = stream.read()) == -1) {
break;
}
System.out.write(character);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}

}

通过上面的代码,我能够实现从 Processes 流中读取而忽略任何孙进程。


使用一段时间后,有几件事需要解决:

  • 我现在改用 InputStreamReader 的一个主要原因是:我可以指定编码。所有出现的 stream.available() > 0 都必须替换为 reader.ready()
  • 这会在闲置时消耗大量资源!如果在尝试再次读取之前没有可读取的内容,则让线程 hibernate 几毫秒是有意义的。
  • 至少在我将每个字符一个一个地发送到我的 GUI 的用例中,这会很快杀死 GUI 以获得更长的输出。在对主线程进行进一步处理之前,考虑为输出设置某种缓冲区。

关于java - 读取输出时如何处理 Java Processes 孙子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51536253/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com