一、应用场景
javaweb程序,服务器(windows)
要求后端一项服务提供图片识别的功能,需要调用python,还用到了tensorflow的框架。
二、场景分析
如果是一般的python程序,有Jython可以尝试,去下一下,捣鼓捣鼓,完全可以。
但是这样的方式是没有其他python工具箱可以用的,像numpy这样常用的包就得另外想办法。
而我这里还用到了tensorflow这样的框架,环境更加复杂了。
本来在网上看到了一个用进程+socket通信的方式解决问题的办法,链接如下:
https://www.cnblogs.com/maosonglin/p/9397257.html
最后我是补了补这个socket,理论上它这种方式有点东西,而且可行,但是我又发现了一个神奇的方式:
java自带有一个Runtime().getRuntime().exec()的方法,这个方法能用cmd/shell的方式执行java的外部程序。
最后就是通过这样的一个方法来解决上述需求的。
三、具体分析
1.Runtime().getRuntime().exec()方法分析
首先要知道这个工具的用法
public Process exec(String command)//在单独的进程中执行指定的字符串命令。
public Process exec(String [] cmdArray)//在单独的进程中执行指定命令和变量
public Process exec(String command, String [] envp)//在指定环境的独立进程中执行指定命令和变量
public Process exec(String [] cmdArray, String [] envp)//在指定环境的独立进程中执行指定的命令和变量
public Process exec(String command,String[] envp,File dir)//在有指定环境和工作目录的独立进程中执行指定的字符串命令
public Process exec(String[] cmdarray,String[] envp,File dir)//在指定环境和工作目录的独立进程中执行指定的命令和变量
这个方法返回一个进程
Process pr=Runtime.getRuntime().exec("cmd");
也就是生成一个进程执行java外部的脚本,方法
通过waitfor()方法来判断进程是否执行错误,返回0成功,1则失败
System.out.println(pr.waitFor());
由于服务器是windows,路径要写反斜杠,写在字符串中就是双反斜杠
通过下方代码来接收.py程序的自然输出
BufferedReader in=new BufferedReader(new InputStreamReader(pr.getInputStream(),"GBK"));
BufferedReader stderrReader = new BufferedReader(new InputStreamReader(pr.getErrorStream(),"GBK"));
String myString=null;
while((myString=in.readLine())!=null)
System.out.println(myString);
System.out.println("ERROR");
while ((myString = stderrReader.readLine()) != null) {
system.out.println(myString);
}
错误流也要接收,不然你看不到哪里错了,而且有流堵塞的问题
使用该方法还有一些注意点,如下文所述:
https://www.jianshu.com/p/af4b3264bc5d
2.实际应用
1.需要执行tensorflow环境下指定的python,首先要找对你的python路径
2.像一般cmd情况下,有两种正确的执行涉及tensorflow环境的.py文件的方法
项目目录: D:\pycharmprojects\project1\im_model.py
tensorflow环境的python.exe目录: D:\anaconda\envs\tensorflow\python.exe
第一种:
#1.进入cmd
#2.激活tensorflow
activate tensorflow
#3.移动到项目的目录下(你想执行的.py文件的路径)
cd /d 项目目录(如 D:/pycharmprojects/project1)
#4.执行你的.py文件
python 全路径的.py文件(如 D:\pycharmprojects\project1\im_model.py)
第二种
#1.进入cmd
#2.移动到项目的目录下(你想执行的.py文件的路径)
cd /d 项目目录
#3.通过tensorflow环境下的python.exe执行.py文件
D:\anaconda\envs\tensorflow\python.exe 项目名称(如im_model.py)
可以先尝试在cmd中正确运行程序,得到结果。
3.java中执行cmd
String myCommand="D:\\anaconda\\envs\\tensorflow\\python.exe im_model.py";
Process pr=Runtime.getRuntime().exec(myCommand,null,new File("D:\\pycharmprojects\\project1"));
可以看到代码中的路径都采用双斜杠,单斜杠会造成语义混乱,如\n等转译字符
采用上述第二种方式,先移动到项目目录,再通过tensorflow环境下的python.exe来执行当前目录下的im_model.py
第二行代码采用如下构造方法
public Process exec(String command,String[] envp,File dir)
第二个参数设null,第三个参数提供项目目录
四.问题
比较有趣的一个问题是
cmd模式下一定要移动到项目目录下,python程序才能正确执行
到了java里,就要先把工作目录设置成项目目录
为什么一定要移动到项目目录下,这是个大大的问题,先挖个大坑。
你们可以尝试一下cmd模式下不移动到项目目录的情况下执行,可能就会失败。
具体失败原因不太清楚。