使用Apache Commons Exec和提取输出向命令提供多个输入的问题 [英] Trouble providing multiple input to a Command using Apache Commons Exec and extracting output

查看:3678
本文介绍了使用Apache Commons Exec和提取输出向命令提供多个输入的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个需要使用Apache Commons Exec库的外部命令行应用程序的Java应用程序。我需要运行的应用程序有相当长的加载时间,所以最好保持一个实例,而不是每次创建一个新的进程。应用程序的工作方式非常简单。一旦开始,它等待一些新的输入,并生成一些数据作为输出,这两个都使用应用程序的标准I / O。

I am writing a Java application that needs to use an external command line application using the Apache Commons Exec library. The application I need to run has a fairly long loading time so it would be preferable to keep one instance alive instead of creating a new process every time. The way the application work is very simple. Once started, it waits for some new input and generates some data as an output, both of which use the application's standard I/O.

所以想法是执行CommandLine,然后使用PumpStreamHandler与三个单独的流(输出,错误和输入),并使用这些流与应用程序交互。到目前为止,我已经在这个工作在基本的情况下,我有一个输入,一个输出和应用程序然后关闭。

So the idea would be to execute the CommandLine, and then to use the PumpStreamHandler with three separate streams (output, error and input) and use those streams to interact with the application. So far, I have had this work in basic scenarios where I have one input, one output and the application then shuts down. But as soon as I'm trying to have a second transaction, something goes wrong.

在创建了我的CommandLine之后,我创建了我的Executor并启动它: / p>

After having created my CommandLine, I create my Executor and launch it like so :

this.executor = new DefaultExecutor();

PipedOutputStream stdout = new PipedOutputStream();
PipedOutputStream stderr = new PipedOutputStream();
PipedInputStream stdin = new PipedInputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(stdout, stderr, stdin);

this.executor.setStreamHandler(streamHandler);

this.processOutput = new BufferedInputStream(new PipedInputStream(stdout));
this.processError = new BufferedInputStream(new PipedInputStream(stderr));
this.processInput = new BufferedOutputStream(new PipedOutputStream(stdin));

this.resultHandler = new DefaultExecuteResultHandler();
this.executor.execute(cmdLine, resultHandler);

然后我继续启动三个不同的线程,每个线程处理不同的流。我还有三个SynchronousQueues处理输入和输出(一个用作输入流的输入,一个用于通知outputQueue已经启动了一个新的命令,一个用于输出)。例如,输入流线程如下所示:

I then proceed to launching three different threads, each of one handling a different stream. I also have three SynchronousQueues that handle input and output (one used as input for the input stream, one to inform the outputQueue that a new command has been launched and one for output). For example, the input stream thread looks like this :

while (!killThreads) {
    String input = inputQueue.take();

    processInput.write(input.getBytes());
    processInput.flush();

    IOQueue.put(input);
}

如果我删除while循环并执行一次,完美。显然,如果我再次尝试执行它,PumpStreamHandler抛出一个异常,因为它已被两个不同的线程访问。

If I remove the while loop and just execute this once, everything seems to work perfectly. Obviously, if I try executing it again, the PumpStreamHandler throws an exception because it has been accessed by two different threads.

这里的问题是,似乎processInput是没有真正冲洗,直到线结束。当调试时,命令行应用程序只有在线程结束时才真正地接收它的输入,但是如果保持while循环,则不会获得它的输入。我尝试了很多不同的东西,使processInput刷新,但没有什么似乎工作。

The issue here is that it seems like the processInput is not truly flushed until the thread ends. When debugged, the command line application only truly receives its input once the thread ends, but never gets it if the while loop is kept. I've tried many different things to get the processInput to flush but nothing seems to work.

有没有人尝试过类似的东西?有什么我失踪了吗?任何帮助将非常感谢!

Has anyone attempted anything similar before? Is there anything I am missing? Any help would be greatly appreciated!

推荐答案

我结束了找出一种方法,使这项工作。通过查看Commons Exec库的代码,我注意到PumpStreamHandler使用的StreamPumpers在每次有新数据传入时都不刷新。这就是为什么代码工作时,我只执行一次,因为它自动刷新和关闭流。所以我创建了一些类,我称之为AutoFlushingStreamPumper和AutoFlushingPumpStreamHandler。后者与普通PumpStreamHandler相同,但使用AutoFlushingStreamPumpers而不是通常的。 AutoFlushingStreamPumper与标准StreamPumper相同,但每次向其写入内容时都会刷新其输出流。

I ended up figuring out a way to make this work. By looking inside the code of the Commons Exec library, I noticed the StreamPumpers used by the PumpStreamHandler did not flush each time they had some new data incoming. This is why the code worked when I executed it just once, since it automatically flushed and closed the stream. So I created classes that I called AutoFlushingStreamPumper and AutoFlushingPumpStreamHandler. The later is the same as a normal PumpStreamHandler but uses AutoFlushingStreamPumpers instead of the usual ones. The AutoFlushingStreamPumper does the same as a standard StreamPumper, but flushes its output stream every time it writes something to it.

我已经测试了它,它似乎工作好。感谢所有试图找出这一点的人!

I've tested it pretty extensively and it seems to work well. Thanks to everyone who has tried to figure this out!

这篇关于使用Apache Commons Exec和提取输出向命令提供多个输入的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆