关于常用的Java调用python的方法:
Process proc;
try {
proc = Runtime.getRuntime().exec(pythonpath + " -u " + pyfilepath);
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gb2312"));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
proc.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
这里有若干地方需要注意,在这里进行说明:
(1)"-u"命令
proc = Runtime.getRuntime().exec(pythonpath + " -u " + pyfilepath);
“-u”命令代表一种实时的操作命令,如果对Java调用python程序有实时要求时,这是必需的;
(2)“GB2312”编码格式
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gb2312"));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
不论是Java还是python,utf-8、gb2312或者gbk格式不统一,都会造成乱码,例如生僻汉字、问号种种;
在这个问题上,首先需要明确python的print输出到控制台的格式是什么,print默认的输出格式为GB2312,
在被Java用缓冲流读取时,其格式发生了改变,因此需要在缓冲流创建时将读取的内容直接转为GB2312。
根据网络上的检索显示,GB2312并非是唯一答案,而取决于每台电脑及使用者的风格,因此需要根据自己的实际情况进行改变。
△需要注意的是,根据调试结果,将GB2312设置在while循环中,即读取line时进行转换是没有效果的,必须在缓冲流创建时就将其转换;
(3)关于jython包
网络上有部分答案误导了jython包的版本,在其注释内往往标注为jython包为2.x或3.x版本,jython包并没有3.x版本,到现在为止最高版本为2.7.x,应该与python包进行区分。
(4)报错问题
用Java调用python的调试过程中,一旦py文件出现了问题,往往不会反映在控制台上,Java将直接跳过py程序;
此外,务必要区分pycharm环境运行py与Java调用python的过程,一是pycharm中下载的包与Java调用py文件时的包并不一致,
如前所述:
proc = Runtime.getRuntime().exec(pythonpath + " -u " + pyfilepath);
这里给出pythonpath与pyfilepath的示例格式(绝对路径):
E:\\python3.11\\Python311\\python.exe
F:\\EquationModelResult\\Python\\SCE_OP.py
这里的python.exe的包应来自于Python311以下,而非Pycharm已经安装的包,需通过pip命令下载。
二是pycharm是一个IDE,可否通过Java直接调用并没有经过尝试;
三是如果代码涉及到数学公式,例如fsolve这类数学运算函数,建议是将pycharm环境中出现的,不会对主程序的运行或计算结果的对错产生灾难性影响的例如runtime warning忽略,本例中忽略方法的代码如下:
import warnings
warnings.filterwarnings("ignore")
根据调试过程,如果这些warning存在,Java在接收到这些warning后将停止运行;
总而言之,Java在调用python时直接跳过py文件较为麻烦,一旦py文件存在错误,Java将无法反映这些错误,因此遇到这种情况最好的办法是回到py文件中。
其次是注意pycharm的包和实际应用的python解译工具的包是不是一致的。
最后关于py文件有一个值得说明的地方是,
我们经常会面临一个py文件调用另一个py文件的情况,这种时候可能出现变量名未定义,即Name Error类似的报错信息。
这里给出的解释是,另一个py文件中的变量通常是局部变量,一旦主py文件调用完毕之后就将销毁,下一次调用时就无法找到这个变量。
解决该问题的方法是,涉及到哪个变量就将这个变量如下表示:
global x
其中x代表任何一个你需要考虑的变量,这句话需要定义在变量赋值之前。
PS:这个变量不局限于自己定义的变量,缩写的包名如numpy-np,或者matplotlib-mp都可能需要在py文件的开头位置定义全局变量;