从Java向C++程序通信

4

我希望能够在Java中执行外部的.exe程序。这个.exe是一个命令行应用程序,它可以在运行时接收输入(scanf())并根据输入输出结果。我可以使用Java调用该程序来执行。

Process p = Runtime.getRuntime().exec("cmd /c start a.exe");

替代
Process p = Runtime.getRuntime().exec("cmd /c start a.exe");

但是我认为也可以从Java中调用程序。 我的整个程序都是用C ++编写的,只需要一个用Java编写的GUI。 需要注意以下几点:

1)与.exe的通信应该是运行时的(而不是通过main(args)) 2)Java程序应该将输出存储在某些变量/面板中以供将来使用 3)要执行的程序可能会有所不同(例如用户可能会选择根本不需要任何输入的.exe) ………因此,基本上Java GUI将充当RuntimeEnv

 public void runEXE() 

       {
            String s = null;

            try {
                Process p = Runtime.getRuntime().exec("cmd /c a.exe");
                System.exit(0);
            }
            catch (IOException e) {
                System.out.println("exception happened - here's what I know: ");
                e.printStackTrace();
                System.exit(-1);
            }

       }

我知道关于这个主题有很多问题。但是我找不到其中任何一个有用的。

7个回答

3
我使用的函数不太好看。它接收要传递给Runtime.getRuntime().exec的命令,然后将结果保存到一个字符串中,并在最后返回该字符串。您可以选择是否只想要最后一行(或所有输出),以及是否希望保存进程的标准输出或标准错误输出字符串。
private static String systemResult(String cmd, boolean append, boolean useErr)
    {
    String result = "";
    try{
        // spawn the external process
        //printCmd(cmd);
        Process proc = Runtime.getRuntime().exec(cmd);
        LineNumberReader lnr1 = new LineNumberReader(new InputStreamReader(proc.getErrorStream()));
        LineNumberReader lnr2 = new LineNumberReader(new InputStreamReader(proc.getInputStream()));
        String line;
        int done = 0;
        while(lnr1 != null || lnr2 != null){
        try{
            if(lnr1.ready()){
            if((line = lnr1.readLine()) != null){
                //System.err.println("A:" +line);
                if(useErr){
                if(append) result = result + line + "\n";
                else result = line;
                }
            }
            }else if(done == 1){
            done = 2;
            }
        }catch(Exception e1){
            try{ lnr1.close(); }catch(Exception e2){}
            lnr1 = null;
        }

        try{
            if(lnr2.ready()){
            if((line = lnr2.readLine()) != null){
                //System.err.println("====>Result: " + line);
                if(!useErr){
                if(append) result = result + line + "\n";
                else result = line;
                }
            }
            }else if(done == 2){
            break;
            }
        }catch(Exception e1){
            try{ lnr2.close(); }catch(Exception e2){}
            lnr2 = null;
        }

        try{
            proc.exitValue();
            done = 1;
        }catch(IllegalThreadStateException itsa){}
        }
        if(lnr1 != null) lnr1.close();
        if(lnr2 != null) lnr2.close();

        try{
        proc.waitFor();
        }catch(Exception ioe){
        }finally{
        try{
            proc.getErrorStream().close();
            proc.getInputStream().close();
            proc.getOutputStream().close();
        }catch(Exception e){}
        proc = null;
        }
    }catch(Exception ioe){
    }
    return result;
    }

1

我会看一下JNI,并使用某种类型的IPC与C++项目进行通信。

更新:

JNI是Java与JRE运行的底层本地环境进行接口的一种方式。这种方法需要您在Java程序启动时创建一个DLL,该DLL将被加载到JRE中。然后,该JNI DLL将包含一个方法,可以从Java程序内部调用该方法,将数据传递到JNI DLL中,然后通过命名管道或共享内存与C++项目进行通信。

命名管道可使用CreateNamedPipe Win32 API创建。在JNI DLL中,您很可能会创建一个服务器,在C++项目中,您会创建一个客户端。请注意,服务器示例是多线程的,但可以轻松转换为单线程模型以简化操作。
请注意,这不是一项简单的任务。其他答案提供了一些更简单的方法,如JNA和通过stdin将数据传递给C++项目。

你在哪个操作系统上运行这个程序? - linuxuser27

1

你可以像@linuxuser27建议的那样使用JNI,或者你可以使用SWIG来帮助简化从Java到C++的通信过程。


1

Google Protocol Buffers 是 Java/C++ 互操作性的好选择。

协议缓冲区是 Google 的语言中立、平台中立、可扩展的机制,用于序列化结构化数据 - 类似 XML,但更小、更快、更简单。您只需定义一次您希望如何组织数据,然后就可以使用特殊生成的源代码轻松地将结构化数据写入和读取到各种数据流中,并使用各种语言(如 Java、C++ 或 Python)。



0

有几件事情:

  • 首先,如果您还没有这样做,请阅读这篇至关重要的文章:当Runtime.exec无法运行
  • 接下来,Java与其他应用程序进行通信的几种方法,可能最简单的是通过标准输入和输出流。您尝试过使用这些吗?
  • 然后是JNI和更容易的JNA,但您说您的C++程序是通过CLI运行的,这表明您有一个.NET dll,而不是真正的Windows dll。是这样吗?如果是这样,Java和C++之间的通信将更加困难。

我似乎找不到一个可以同时进行输入输出的程序。 - shababhsiddique
@shababhsiddique:你需要使用单独的线程来完成这个任务。我上面链接的文章的最后一页展示了一个简单的例子。 - Hovercraft Full Of Eels
1
最好从Oracle Java线程和其他Java基础教程开始学习,否则你将会遇到很多痛苦,因为你的学习顺序是错误的。在尝试将Java与C/C++结合之前,先学习如何使用线程和Java基础知识。 - Hovercraft Full Of Eels

0
  1. 您可以直接执行 .exe 程序。只需提供完整路径即可。相对路径也可以。

  2. 您可以使用管道与外部进程进行交互:发送命令输入, 读取命令输出


你可以将这两个示例合并到一个程序中。注意,由于它使用阻塞读取(read()),所以需要在单独的线程中执行输入。 - Peter Knego
这就是我的问题.. 如何? - shababhsiddique
1
在这个例子中,类似于StreamGobbler的东西:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 - Peter Knego

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接