我知道以前曾经问过这个问题,但是,有时人们会碰巧,其他答案似乎没有帮助。
我需要启动一个C应用程序并传递一些输入来浏览其菜单以最终执行我需要的内容。最终输出(结果)被发送到一个文件,但是中间输出(打印在控制台上的菜单和子菜单)可以很好地打印在我的Eclipse控制台上进行调试。
我根据用户Vince posted on his question以及之后提到的用户编写了以下代码,但它似乎并没有为我做。
public final class InteractWithExternalApp {
private static PrintWriter printOut;
private static BufferedReader retrieveOutput;
private static Process p;
private EvaluationTests(){} // suppressing the class constructor
public static void Evaluate(String paramToApp) {
try
{
Runtime rt = Runtime.getRuntime() ;
p = rt.exec("C:\\Path\\To\\Desktop\\appName " + paramToApp);
InputStream in = p.getInputStream() ;
OutputStream out = p.getOutputStream ();
retrieveOutput = new BufferedReader(new InputStreamReader(in));
printOut = new PrintWriter(out);
// print menu
if((line = retrieveOutput.readLine()) != null) {
System.out.println(line);
}
// send the input choice -> 0
printOut.println("0");
printOut.flush();
// print sub-menu
if((line = retrieveOutput.readLine()) != null) {
System.out.println(line);
}
// send the input choice
printOut.println("A string");
printOut.flush();
// print sub-menu
if((line = retrieveOutput.readLine()) != null) {
System.out.println(line);
}
/*
Repeat this a few more times for all sub-menu options until
the app finally executes what's needed
*/
}catch(Exception exc){
System.out.println("Err " + exc.getMessage());
}
return;
}
此外,作为练习,我尝试按照给定here的示例打开Windows命令提示符并向其发送命令。 cmd.exe打开正常,但随后传递echo
命令没有做任何事情。
OutputStream stdin = p.getOutputStream();
InputStream stdout = p.getInputStream();
stdin.write(new String("echo test").getBytes());
stdin.flush();
任何人都可以降手吗?我哪里错了?
答案 0 :(得分:2)
我不想说我100%肯定,但我99%确信问题在于Java和C程序的输入和输出流之间的连接。我能够启动程序,但无法通过我需要的参数。
确实使用ProcessBuilder
来解决问题。感谢您唆使我回到我之前找到的解决方案@Jayan。
所以这是最终的代码:
public final class InteractWithExternalApp {
private static BufferedReader inputReader, errorReader;
private static OutputStream outputStream;
private static PrintStream printOutputStream;
private InteractWithExternalApp (){} // suppressing the class constructor
public static void Evaluate(String paramToApp) {
System.out.println("Running evaluation tests...");
try
{
ProcessBuilder pb = new ProcessBuilder("Path/to/my/C/application", "paramToApp");
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
Process process = pb.start();
String line;
errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while((line = errorReader.readLine()) != null){
System.out.println(line);
}
inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while((line = errorReader.readLine()) != null){
System.out.println(line);
}
outputStream = process.getOutputStream();
printOutputStream = new PrintStream(outputStream);
printOutputStream.println("A parameter"); printOutputStream.flush();
printOutputStream.println("Another parameter"); printOutputStream.flush();
printOutputStream.println("And however many more I would need to finally get where I wanted"); printOutputStream.flush();
inputReader.close();
errorReader.close();
printOutputStream.close();
} catch(IOException ioe){
System.out.println("Error during evaluation routine: " + ioe.getMessage());
} finally {
System.out.println("Evaluation complete!");
}
return;
}
因为我还没有足够的声誉,所以"投票"答案,我在此正式向@Benjamin Gruenbaum和@samaitra表示感谢,他们将答案发给this question,我从中得到了解决方案。
我希望这对其他人也有帮助。
答案 1 :(得分:0)
当readLine()在其末尾没有“\ n”时挂起是一个问题.... 有很多方法可以给这只猫皮肤,但这是最简单的恕我直言(高效的)... 使用nio CharBuffer而不是readLine(),它(读取(CharBuffer))将很乐意在最后丢失换行符,并且可能会捕获您需要的所有内容。如果您知道您的应用程序将在中间暂停,请根据需要添加一些Thread.sleep()调用以确保您获得所有内容。小心的评论正在显示
代码对于可读性而言是不必要的冗长,根据需要崩溃:
Thread.sleep(1000) //sleep for a sec to make sure the app started outputting
final CharBuffer cb = CharBuffer.allocate(1024 * 1024); // I set a 1mb for the buffer, but it's probably excessive
boolean canPrint = true;
// print menu
String data;
while (canPrint) {
if (retrieveOutput.ready()) {
cb.clear();
if (retrieveOutput.read(cb) != -1) {
cb.flip();
data = cb.toString();
cb.flip();
final String[] params = data.split("\n"); //split the output back into lines (not really needed)
for (final String line : params) {
LOG.info(line.replace("\r", "")); // these will be there on windows but not Unix or OSX
}
Thread.sleep(1000) //sleep for a sec to see if more output will be added
} else {
canPrint = false;
}
} else {
canPrint = false;
}
}
HTH,