首页 文章

在Windows中:从C程序获取无缓冲的stdout到Java程序InputStream [现在用最少的例子!]

提问于
浏览
1

SOLVED:

HovecraftFullOfEels发现了我的错误 . 请参阅下面的答案评论 . 我应该调用start()时在Thread对象上调用run() . 在我的原始程序中,这意味着它在stderr上被阻止,直到程序退出然后立即获得stdout .

UPDATE:

根据要求,我已经制作了一个最小的例子 . 这是制作人:

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

预期的行为:由于 生产环境 者刷新其输出并且消费者完全没有缓冲,消费者应该实时获得 生产环境 者的输出 .

观察到的行为:消费者只有在 生产环境 者完成时才会立即收到 生产环境 者的输出 .

Original post

我正在与Windows应用程序上的另一个开发人员合作 . 她编写了一个C程序(我们可以修改),它执行媒体转换并将进度消息(百分比)打印到stdout . 我正在用Java编写图形前端,我希望我的程序捕获这些消息并更新GUI元素 .

相关的C程序代码如下所示:

printf ("progress_msg: %d%%\n", currentProgress);
fflush(stdout);

在Java程序中,我使用 Runtime.getRuntime().exec() 来运行C程序并抓取原始的InputStream对象,用于解析stdout流的C程序's stdout and stderr. (The stderr is just being thrown away by another thread.) I',查找这些消息(好吧,我是,使用BufferedReader,但是现在,我'm trying to debug this, so I'm直接与低级InputStream字节源通信 . )

问题是虽然Java端没有缓冲(我知道)并且C程序中有 fflush ,但只有当C程序完成时才会出现stdout文本 . 当我从命令提示符运行它时,这与消息不同,消息按预期逐渐出现 .

那么清楚,有_654604知道吗?如果是这样,有没有办法把它关掉? Windows中的 fflush(stdout) 无法按预期方式工作吗?什么是正确的Windows等价物?

谢谢 .

注意:我找到了两个相关的stackoverflow,但他们没有回答这个问题 . 特别是,我们可以修改C程序,没有行缓冲,我们正在进行适当的刷新(据我们所知) . 见I want realtime output of my Runtime.getRuntime().exec()Unbuffered subprocess stdout on windows .

1 回答

  • 1

    我的一个疯狂的猜测,但你说:

    ...我正在用Java编写图形前端,我希望我的程序捕获这些消息并更新GUI元素 . ...在Java程序中,我使用Runtime.getRuntime() . exec()来运行C程序并获取C程序的stdout和stderr的原始InputStream对象 . ...我正在解析stdout流,寻找那些消息......问题是虽然Java端没有缓冲(我知道)并且在C程序中有一个fflush,但是出现了stdout文本只有在C程序结束时才会同时出现 .

    我再次猜测,因为你遗漏了重要的细节,所有代码,但如果你的前端是一个Swing GUI,那么你所描述的症状表明你正在尝试获取有关Swing事件线程的所有信息 . 如果这是一个Swing应用程序,解决方案是确保在后台线程(例如SwingWorker提供的线程)中读取Stream的输出,以确保缓冲您正在读取的数据,然后以线程安全的方式在GUI中显示它(再次使用SwingWorker,尤其是其发布/进程方法对) .

    为了获得更好的帮助,请向我们提供更好的信息和代码,最好是一小部分,实际上是最小的,我们可以运行,测试和改进 .


    Edit
    我的测试程序:

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

相关问题