在Windows中:从C程序中获取无缓冲的stdout到Java程序InputStream

解决了:

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(); } } }