如何从我的Java应用程序中与C控制台应用程序进行交互

时间:2014-11-01 05:23:04

标签: java process console-application interaction external-process

我知道以前曾经问过这个问题,但是,有时人们会碰巧,其他答案似乎没有帮助。

我需要启动一个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();

任何人都可以降手吗?我哪里错了?

2 个答案:

答案 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,