我有一个python脚本,需要很长时间才能完成。我想从 Java 运行它,但也要在执行时输出脚本的输出,以便我可以判断它是否正常运行。
我搜索过,只找到了我们在系统命令完成后而不是在其执行期间输出输出的示例。
有什么方法可以在脚本运行时执行此操作?
这是我所拥有的
public void doSomething() throws IOException {
String[] callAndArgs = {"python", "/hi.py"};
Process p = Runtime.getRuntime().exec(callAndArgs);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
我设法让它像这样工作(注意它需要java7(:
package test;
import java.lang.ProcessBuilder.Redirect;
public class Test {
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("python","/home/foobar/Programming/test/src/test/test.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
p.waitFor();
}
}
python(注意我在Python上刷新以使其使用sys.stdout.flush((工作(
import time,sys
c =0
while c<=50:
time.sleep(1)
print("----")
c = c +1
sys.stdout.flush()
请注意,如果您不想在循环中刷新,则可以使用以下命令:
ProcessBuilder pb = new ProcessBuilder("python","-u","/home/foobar/Programming/NetBeansProjects/test/src/test/test.py");
重定向.继承
指示子进程 I/O 源或目标将与当前进程的 I/O 源或目标相同。这是大多数操作系统命令解释器 (shell( 的正常行为。
我搜索过,只找到了我们在之后输出输出的示例 系统命令已完成,而不是在其执行过程中完成。
这很奇怪,因为您的示例应该在执行命令时转储输出。
您可以尝试直接从InputStream
读取,而不是使用 BufferedReader
,因为直到进程退出后才能满足 readLine 所需的条件。
我还建议您直接使用 ProcessBuilder
而不是 Process
,因为除了其他任何事情之外,它还允许您将错误流的输出重定向到输入流中,允许您只读取一个流而不是两个......
这也可能是 Python 的问题以及它如何刷新输出缓冲区......
例如,与其等待BufferedReader
决定何时返回,不如尝试在发生/报告流时打印流中的每个字符
ProcessBuilder pb = new ProcessBuilder("test.py");
pb.redirectError();
Process p = pb.start();
InputStream is = null;
try {
is = p.getInputStream();
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char)in);
}
} finally {
try {
is.close();
} catch (Exception e) {
}
}
更新
稍微阅读一下,Python似乎在将其发送到标准输出之前将其缓冲出来。 我不认为你可以在Java方面解决这个问题,但需要改变Python的运行方式或脚本的工作方式。
有关更多详细信息,请参阅如何刷新 Python 打印的输出?
我怀疑你正在写信给stderr,你看不到它,因为你在stdin上被阻止了。使用 ProcessBuilder 而不是执行 exec
。这样,您可以将 stderr 和 stdin 重定向到单个流中。
下面是一个示例:
import java.io.*;
public class Test {
public static void main(String... args) throws IOException {
ProcessBuilder pb =
new ProcessBuilder("test.py");
pb.redirectErrorStream(true);
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader bf = new BufferedReader(reader);
String s;
while ((s = bf.readLine()) != null) {
System.out.println(s);
}
}
}
或者,您可以生成线程以分别从 stdin/stderr 读取。
要寻找的另一件事是 python 的输出缓冲。您可以通过执行以下操作来查看这是否是原因:
import sys
sys.stdout.flush()
写信给标准输出之后
不要在 while 循环中使用 #readLine 作为条件。而是将您的输入流包装在扫描仪中并使用 #hasNextLine((
Scanner in = new Scanner(p.getInputStream());
while (in.hasNextLine()) {
System.out.println(in.nextLine());
}