在 Java 中调用并接收 Python 脚本的输出?
- 2025-03-20 08:47:00
- admin 原创
- 46
问题描述:
从 Java 执行 Python 脚本并接收该脚本的输出的最简单方法是什么?我寻找过不同的库,如 Jepp 或 Jython,但大多数都已过时。这些库的另一个问题是,如果我使用库,我需要能够轻松地将库包含在源代码中(尽管我不需要为库本身提供源代码)。
因此,最简单/最有效的方法是否只是简单地使用runtime.exec调用脚本,然后以某种方式捕获打印的输出?或者,即使这对我来说非常痛苦,我也可以将Python脚本输出到临时文本文件中,然后用Java读取该文件。
注意:Java 和 Python 之间的实际通信不是我要解决的问题的必要条件。然而,这是我能想到的唯一一种可以轻松完成所需操作的方法。
解决方案 1:
不确定我是否正确理解了您的问题,但只要您可以从控制台调用 Python 可执行文件并且只想在 Java 中捕获其输出,您就可以使用exec()
JavaRuntime
类中的方法。
Process p = Runtime.getRuntime().exec("python yourapp.py");
您可以从此资源中了解如何实际读取输出:
http://www.devdaily.com/java/edu/pj/pj010016
import java.io.*;
public class JavaRunCommand {
public static void main(String args[]) {
String s = null;
try {
// run the Unix "ps -ef" command
// using the Runtime exec method:
Process p = Runtime.getRuntime().exec("ps -ef");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:
");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):
");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
System.exit(-1);
}
}
}
还有一个 Apache 库(Apache exec 项目)可以帮助您实现这一点。您可以在此处阅读更多相关信息:
http://www.devdaily.com/java/java-exec-processbuilder-process-1
http://commons.apache.org/exec/
解决方案 2:
您可以在 Java 项目中包含Jython库。您可以从 Jython 项目本身下载源代码。
Jython 确实提供了对JSR-223 的支持,这基本上允许您从 Java 运行 Python 脚本。
您可以使用ScriptContext
来配置您想要发送执行输出的位置。
例如,假设在名为的文件中有一个以下 Python 脚本numbers.py
:
for i in range(1,10):
print(i)
因此,您可以按如下方式从 Java 运行它:
public static void main(String[] args) throws ScriptException, IOException {
StringWriter writer = new StringWriter(); //ouput will be stored here
ScriptEngineManager manager = new ScriptEngineManager();
ScriptContext context = new SimpleScriptContext();
context.setWriter(writer); //configures output redirection
ScriptEngine engine = manager.getEngineByName("python");
engine.eval(new FileReader("numbers.py"), context);
System.out.println(writer.toString());
}
输出结果为:
1
2
3
4
5
6
7
8
9
只要您的 Python 脚本与 Python 2.5 兼容,使用 Jython 运行它就不会遇到任何问题。
解决方案 3:
我之前也遇到过同样的问题,也看过这里的答案,但没有找到一个令人满意的解决方案可以平衡兼容性,性能和良好的格式输出,Jython 不能与扩展 C 包一起使用并且比 CPython 慢。所以最后我决定自己发明轮子,花了我 5 个晚上,希望它也能帮助你:jpserve( https://github.com/johnhuang-cn/jpserve )。
JPserve 提供了一种简单的方法来调用 Python,并以格式良好的 JSON 来交换结果,性能损失很小。以下是示例代码。
首先,在 Python 端启动 jpserve
>>> from jpserve.jpserve import JPServe
>>> serve = JPServe(("localhost", 8888))
>>> serve.start()
INFO:JPServe:JPServe starting...
INFO:JPServe:JPServe listening in localhost 8888
然后从JAVA端调用Python:
PyServeContext.init("localhost", 8888);
PyExecutor executor = PyServeContext.getExecutor();
script = "a = 2
"
+ "b = 3
"
+ "_result_ = a * b";
PyResult rs = executor.exec(script);
System.out.println("Result: " + rs.getResult());
---
Result: 6
解决方案 4:
Jep是另一个选择。它通过 JNI将CPython嵌入到 Java 中。
import jep.Jep;
//...
try(Jep jep = new Jep(false)) {
jep.eval("s = 'hello world'");
jep.eval("print(s)");
jep.eval("a = 1 + 2");
Long a = (Long) jep.getValue("a");
}
解决方案 5:
我寻找过不同的库,例如 Jepp 或 Jython,但大多数似乎都已经过时了。
Jython 不是“一个库”;它是在 Java 虚拟机之上实现的 Python 语言。它绝对没有过时;最新版本是今年 2 月 24 日发布的。它实现了 Python 2.5,这意味着您将缺少几个较新的功能,但老实说,它与 2.7 并没有太大区别。
注意:Java 和 Python 之间的实际通信不是上述作业的要求,因此这对我来说不算是家庭作业。然而,这是我能想到的唯一一种轻松完成所需任务的方法。
对于学校作业来说,这种情况似乎极不可能发生。请告诉我们您真正想做什么。通常,学校作业会明确说明您将使用哪些语言来做什么,我从未听说过涉及多种语言的作业。如果有,他们会告诉您是否需要建立这种交流,以及他们打算如何做。
解决方案 6:
Jython 方法
Java 应该是独立于平台的,而调用本机应用程序(如 python)并不是非常独立于平台的。
有一个用 Java 编写的 Python 版本 (Jython),它允许我们将 Python 嵌入到我们的 Java 程序中。通常,当您要使用外部库时,一个障碍是编译并正确运行它,因此我们经历了使用 Jython 构建和运行简单 Java 程序的过程。
我们首先获取 jython jar 文件:
https://www.jython.org/download.html
我将 jython-2.5.3.jar 复制到 Java 程序所在的目录中。然后我输入以下程序,它的作用与前两个程序相同;获取两个数字,将它们发送给 python,python 将它们相加,然后 python 将其返回给我们的 Java 程序,在那里数字输出到屏幕上:
import org.python.util.PythonInterpreter;
import org.python.core.*;
class test3{
public static void main(String a[]){
PythonInterpreter python = new PythonInterpreter();
int number1 = 10;
int number2 = 32;
python.set("number1", new PyInteger(number1));
python.set("number2", new PyInteger(number2));
python.exec("number3 = number1+number2");
PyObject number3 = python.get("number3");
System.out.println("val : "+number3.toString());
}
}
我将此文件命名为“test3.java”,保存它,然后执行以下操作来编译它:
javac -classpath jython-2.5.3.jar test3.java
下一步是尝试运行它,我的操作方式如下:
java -classpath jython-2.5.3.jar:. test3
现在,我们可以通过 Java 以独立于平台的方式使用 Python。速度有点慢。不过,这很酷,因为它是一个用 Java 编写的 Python 解释器。
解决方案 7:
ProcessBuilder 非常易于使用。
ProcessBuilder pb = new ProcessBuilder("python","Your python file",""+Command line arguments if any);
Process p = pb.start();
这应该调用 python。请参阅此处的过程方法以获取完整示例!
https://bytes.com/topic/python/insights/949995- Three-ways-run-python-programs-java
解决方案 8:
您可以尝试使用 groovy。它在 JVM 上运行,并且对运行外部进程和提取输出提供了强大的支持:
http://groovy.codehaus.org/Executing+External+Processes+From+Groovy
您可以从同一链接中的代码中看到 groovy 如何轻松获取流程状态:
println "return code: ${ proc.exitValue()}"
println "stderr: ${proc.err.text}"
println "stdout: ${proc.in.text}" // *out* from the external program is *in* for groovy
解决方案 9:
首先我建议使用 ProcessBuilder (自 1.5 开始)
简单的用法描述在这里
https://stackoverflow.com/a/14483787
有关更复杂示例,请参阅
http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html
我在从 Java 启动 Python 脚本时遇到了问题,脚本向标准输出产生了太多输出,一切都变得糟糕。
解决方案 10:
最好的实现方式是使用 Apache Commons Exec,因为我将它用于生产并且没有任何问题,即使在 Java 8 环境中也是如此,因为它允许您使用看门狗以任何方式synchronous
执行任何外部进程(包括 python、bash 等)。asynchronous
CommandLine cmdLine = new CommandLine("python");
cmdLine.addArgument("/my/python/script/script.py");
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
ExecuteWatchdog watchdog = new ExecuteWatchdog(60*1000);
Executor executor = new DefaultExecutor();
executor.setExitValue(1);
executor.setWatchdog(watchdog);
executor.execute(cmdLine, resultHandler);
// some time later the result handler callback was invoked so we
// can safely request the exit value
resultHandler.waitFor();
这里分享了一个小但完整的 POC 的完整源代码,解决了这篇文章中的另一个问题;
扫码咨询,免费领取项目管理大礼包!