解决了:
HovecraftFullOfEels发现我的错误。 请参阅下面对他的回答的评论。 当我调用start()时,我正在调用Thread对象的run()方法。 在我原来的程序中,这意味着它阻止了stderr,直到程序退出,然后立刻得到标准输出。
更新:
按照要求,我制作了一个简单的例子。 这是制片人:
package producer; public class Producer { public static void main(String[] args) throws InterruptedException { for (int i=0; i<10; i++) { System.out.println(i); System.out.flush(); Thread.sleep(1000); } } }
这是消费者:
package consumer; import java.io.IOException; import java.io.InputStream; public class Consumer { static class Dumper extends Thread { InputStream r; boolean print; Dumper(InputStream r, boolean print) { this.r = r; this.print = print; } @Override public void run() { int c; try { while ((c = r.read()) != -1) { if (print) System.out.print((char)c); } r.close(); } catch (IOException ex) {} } } public static void main(String[] args) throws Exception { Process p = Runtime.getRuntime().exec("java -jar C:\\Users\\millerti\\Documents\\NetBeansProjects\\Producer\\dist\\Producer.jar"); new Dumper(p.getErrorStream(), false).run(); new Dumper(p.getInputStream(), true).run(); p.waitFor(); } }
预期的行为:由于生产者冲洗其产出,消费者完全没有缓冲,消费者应该实时获得生产者的产出。
观察到的行为:消费者只有在生产者完成时才能一次性收到生产者的产量。
原文 :
我正在与Windows应用程序上的另一个开发人员合作。 她已经编写了一个C程序(我们可以修改)执行媒体转换,并将进度消息(百分比)打印到标准输出。 我正在用Java编写一个graphics前端,我希望我的程序能够捕获这些消息并更新一个GUI元素。
相关的C程序代码如下所示:
printf ("progress_msg: %d%%\n", currentProgress); fflush(stdout);
在Java程序中,我使用Runtime.getRuntime().exec()
来运行C程序,并抓取C程序stdout和stderr的原始InputStream对象。 (stderr正在被另一个线程扔掉)我正在parsingstdoutstream,寻找这些消息(当然,我正在使用一个BufferedReader,但现在,我试图debugging这个, m直接与低级别的InputStream字节源进行通信。)
问题是,尽pipe在Java程序中没有缓冲(我知道),并且在C程序中有一个fflush
,但是只有当C程序完成时,stdout文本才会一次出现。 这是不同的,当我从命令提示符运行它,其中消息如期出现。
很明显,有一些缓冲正在进行。 Java中的Process工具正在做一些我不知道的缓冲? 如果是这样,有没有办法把它关掉? Windows中的fflush(stdout)
不能按照预期的方式工作吗? 什么是适当的Windows相当于?
谢谢。
注:我已经find了两个相关的stackoverflows,但他们不回答这个问题。 特别是,我们可以修改C程序,没有行缓冲,我们正在做一个适当的冲洗(据我们所知)。 看到我想 在Windows上 实时输出我的Runtime.getRuntime()。exec()和Unbufferedsubprocess标准输出 。
从我的角度来看,这是一个疯狂的猜测,但你说:
… 我正在用Java编写一个图形前端 ,我希望我的程序捕获这些消息并更新一个GUI元素。
…在Java程序中,我使用Runtime.getRuntime()。exec()来运行C程序,并抓取C程序stdout和stderr的原始InputStream对象。 …我解析stdout流,寻找这些消息…
问题是,尽管在Java程序中没有缓冲(我知道),并且在C程序中有一个fflush,但是只有当C程序完成时,stdout文本才会一次出现。
我再次必须猜测,因为你已经遗漏了重要的细节,所有的代码,但是如果你的前端是一个Swing GUI,那么你描述的症状表明你试图获得关于Swing事件线程的所有信息。 如果这是一个Swing应用程序,解决方案是确保在SwingWorker提供的后台线程中读取Stream的输出,以确保缓冲正在读取的数据,然后以线程安全的方式将其显示在GUI中(再次使用SwingWorker,特别是其发布/处理方法对)。
为了获得更好的帮助,请给我们提供更好的信息和代码,最好是一个小的,实际上最小的,我们可以运行,测试和改进的示例程序 。
编辑
我的测试程序:
import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Consumer { static class StreamGobbler implements Runnable { private String name; private boolean print; private Scanner scanner; public StreamGobbler(String name, InputStream inputStream, boolean print) { this.name = name; this.print = print; scanner = new Scanner(inputStream); } @Override public void run() { System.out.printf("in %s run method%n", name); while (scanner.hasNextLine()) { String line = scanner.nextLine(); if (print) { String output = String.format("From %s: %s%n", name, line); System.out.printf(output); } } if (scanner != null) { scanner.close(); } } } private static final String PRODUCER_PATH = "C:/Users/Pete/Documents/Fubar/Java/producer.jar"; public static void main(String[] args) { List<String> command = new ArrayList<>(); command.add("java.exe"); command.add("-jar"); command.add(PRODUCER_PATH); try { ProcessBuilder pBuilder = new ProcessBuilder(command); Process process = pBuilder.start(); StreamGobbler errorGobbler = new StreamGobbler("Error Gobbler", process.getErrorStream(), true); StreamGobbler inputGobbler = new StreamGobbler("Input Gobbler", process.getInputStream(), true); new Thread(errorGobbler).start(); new Thread(inputGobbler).start(); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }