Java应用程序与Python应用程序之间的交互

3

我有一个Python应用程序,但是从我的角度来看,它是一个黑盒子,我无法编辑。这个Python应用程序知道如何处理文本并返回已处理的文本。

我还有另一个Java编写的应用程序,它知道如何收集未经处理的文本。

当前状态是,Python应用程序每x分钟以批处理模式运行。

我想将Python处理部分作为流程的一部分:Java应用程序收集文本并请求Python应用程序进行处理,并返回已处理的文本。

你认为最简单的解决方案是什么?

谢谢, Rod


Python程序如何接收输入?这听起来有点不太合理,它是每隔X分钟从目录中读取还是从STDIO中读取?您是自己执行代码还是怎么做的? - Petriborg
6个回答

7

我对Jython等技术一无所知,但我猜如果你可以在Java应用程序需要转换文本时不执行新进程而执行两个程序,这可能是最佳解决方案。无论如何,一个简单的概念证明是从Java应用程序执行单独的进程使其工作。接下来,您可以使用所有这些工具增强执行。

从Java执行单独的进程

String[] envprops = new String[] {"PROP1=VAL1", "PROP2=VAL2" };
Process pythonProc = Runtime.getRuntime().exec(
   "the command to execute the python app", 
    envprops, 
    new File("/workingdirectory"));

// get an outputstream to write into the standard input of python
OutputStream toPython = pythonProc.getOutputStream();

// get an inputstream to read from the standard output of python
InputStream fromPython = pythonProc.getInputStream();

// send something
toPython.write(.....);
// receive something
fromPython.read(....);

重要提示:字符和字节不同

许多人低估了这一点。

在进行字符到字节的转换时要小心(记住Writers/Readers是为字符设计的,Input/OutputStreams是为字节设计的,编码是必要的转换方式,您可以使用OuputStreamWriter将字符串转换为字节并发送,InputStreamReader用于将字节转换为字符并读取它们)。


当然,这意味着Python应用程序必须从stdin读取并写入stdout。祝你好运! - helios
它不会只返回Python进程的退出代码吗? 如果不是,那么从inputStream中可以获得什么? - Rod
从调用的(Python)进程中,您有一个STDIN和一个STDOUT(还有一个STDERR :)。 Java可以挂钩它们,在其中一个中写入并读取另一个。当您执行printf(“…”)(抱歉,我不知道Python)时,您正在写入stdout。当您在Windows命令行中执行类似“dir | more”的操作或在Linux中执行“ls | nl”时,您正在将第一个程序的STDOUT重定向到第二个程序的STDIN。如果您想要进程的返回代码,则必须调用pythonProc.waitFor()。那会返回一个int。 - helios

6
使用 ProcessBuilder 来执行你的 Python 代码作为过滤器:
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class PBTest {

    public static void main(String[] args) {
        ProcessBuilder pb = new ProcessBuilder(
            "python3", "-c", "print(42)");
        pb.redirectErrorStream(true);
        try {
            Process p = pb.start();
            String s;
            BufferedReader stdout = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
            while ((s = stdout.readLine()) != null) {
                System.out.println(s);
            }
            System.out.println("Exit value: " + p.waitFor());
            p.getInputStream().close();
            p.getOutputStream().close();
            p.getErrorStream().close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

6

您可以尝试使用Jython - 这个工具可以让您直接在Java代码中运行Python程序,并且可以无缝地来回交互。


即使不改变您的Python代码,您也应该能够使Jython正常工作。 - Steven Schlansker
我想把Python当作一个黑盒子来处理,更像是一个服务器。 Python在套接字方面表现如何? - Rod
@Rod:Jython是在JVM上运行的Python,它仍然是一个“黑盒子”。只是Java可以调用它而不使用套接字等。既然你正在使用Java,这是最好的方法。 - Tor Valamo
我是否需要将Python应用程序代码嵌入到Java应用程序中?还是它可以作为中间技术使用? - Rod
1
如果Python代码依赖于任何C扩展(例如numpy),则Jython将无法工作。此外,Jython中并不存在所有的Python功能,这会导致像NLTK中的这个错误(http://bugs.jython.org/issue1398)一样的错误。尝试在Jython上运行不会有什么损失,但我个人会使用启动单独进程的解决方案之一。 - John Paulett

0

将其中一个作为某种服务公开,可能是Web服务。另一个选项是将Python代码移植到Jython。


0

一个可能的解决方案是使用jpype。这允许您从Python启动JVM并在它们之间传递数据。

另一个解决方案可能是将Python程序编写为过滤器(从stdin读取数据并将结果写入stdout),然后作为管道运行。但是我不知道Java对此的支持情况-根据Sun文档,他们的管道概念仅支持同一JVM上线程之间的通信。


0
一个选项是将Python应用程序作为服务器运行,通过套接字(TCP)监听请求。

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