【问题标题】:JAVA interaction with CPythonJAVA与CPython的交互
【发布时间】:2016-09-12 07:49:01
【问题描述】:

我的目标:

当我从命令行运行 Python (CPython)(不是 Jython,因为它不支持 NumPy 之类的某些包)时,我可以交互地编写代码行并从其输出中查看结果。

我的目标是在 JAVA 中以编程方式执行此操作。这是我的尝试:

代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class PythonProcess {
    private Process proc;
    private BufferedReader stdInput;
    private BufferedReader stdError;
    private BufferedWriter stdOutput;

    public PythonProcess() {
        Runtime rt = Runtime.getRuntime();
        String[] commands = { "python.exe" };
        try {
            proc = rt.exec(commands);
            stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
            stdOutput = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String executeCommand(String command) throws IOException {
        stdOutput.write(command + "\n");
        stdOutput.newLine();
        String s = null;
        StringBuffer str = new StringBuffer();
        while ((s = stdInput.readLine()) != null) {
            str.append(s);
        }
        return str.toString();
    }

    public void initialize() throws IOException {
        // will create a file - if correctly executed in python 
        stdOutput.write("f = open('c:/downloads/deleteme.txt','w')");
        stdOutput.newLine();
        stdOutput.write("f.write('hi there, I am Python \n')");
        stdOutput.newLine();
        stdOutput.write("f.close()");
        stdOutput.newLine();
        stdOutput.flush();
    }

    public static void main(String[] args) throws IOException {
        PythonProcess proc = new PythonProcess();
        proc.initialize(); // time demanding initialization
        for (int i = 0; i < 10; i++) {
            String out = proc.executeCommand("print \"Hello from command line #"+i+"\"");
            System.out.println("Output: " + out);
        }
    }
}

问题:

似乎在initialize()方法中stdOutput传递的代码根本没有被Python执行,因为文件c:/downloads/deleteme.txt没有被创建。稍后在调用 executeCommand 方法时,我也无法从 stdInput 读取任何输出。

问题:

  1. 有什么简单的方法可以修复代码吗?
  2. 谁能指出我如何与 python 交互的一些例子,例如通过客户端 - 服务器方式
  3. 还是有其他想法?

BTW1:Jython 不是要走的路,因为我需要执行 python 不支持的 CPython 指令。


BTW2:我知道我可以通过 String[] commands = { "python.exe" "script.py"}; 以非交互方式执行 python 脚本。问题是当初始化花费大量时间时,这将意味着严重的性能问题。

【问题讨论】:

  • 不过,重新发明轮子听起来很糟糕。您正在处理哪些 Jython 无法处理的 CPython 语句?
  • 我需要 numpy 库:import numpy as np 导致 javax.script.ScriptException: ImportError: No module named numpy in
  • 然后看这里:stackoverflow.com/questions/19455100/… ...并提示:下次尝试自己将“numpy”和jython等词添加到您最喜欢的搜索引擎中...

标签: java python process cpython


【解决方案1】:

很遗憾,无法与 Python 进程直接交互。取而代之的是使用 TCP 套接字的解决方案:

PythonServer.java

package pythonexample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PythonServer {
    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder   ps=new ProcessBuilder("python.exe","tcpServer.py");
        ps.redirectErrorStream(true);
        System.out.println("Starting Python server.");
        Process pr = ps.start();  

        BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            System.out.println(line);
        }
        pr.waitFor();

        in.close();
        System.exit(0);
    }
}

tcpServer.py

import socket

# DO INITIALIZATION

TCP_IP = '127.0.0.1'
TCP_PORT = 5006
BUFFER_SIZE = 20  # Normally 1024, shorter if we want fast response

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)

while 1:
    print 'Waiting for connection'
    conn, addr = s.accept()
    print 'Connection address:', addr
    if addr[0] == '127.0.0.1': # security - only local processes can connect
        data = conn.recv(BUFFER_SIZE)
        print "received data:", data
        res = eval(data)
        print "Sending result:", res
        conn.send("This is reply from Python " + str(res) + "\n")
conn.close()

PythonClient.java

package pythonexample;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class PythonClient {
    public static void main(String[] args) throws IOException {
        String serverAddress = "127.0.0.1";
        Socket s = new Socket(serverAddress, 5006);

        // do this in loop if needed
        String result = sendCommand(s, "1+1                                    \n");
        System.out.println("Received result: "+result);

        // closing socket 
        s.close();
    }

    private static String sendCommand(Socket s, String command) throws IOException {
        BufferedWriter ouput = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        ouput.write(command);
        ouput.flush();

        BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String answer = input.readLine();
        return answer;
    }
}

首先执行 PythonServer 类,初始化服务器。然后执行 PythonClient 将数据发送到服务器并获取结果。

当然,NumPy 和其他不支持的所有功能,例如Jython 现已推出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    相关资源
    最近更新 更多