最近做了一個東西,需要在java應用調用python的函數。查了網上若干資料,有很多種方法(直接用Jython,etc.),親測兩種最有效的方法在此分享一下。
1.使用Runtime.getRuntime()執行腳本文件
該方法可以運行含有python第三方庫的程序
先建立python腳本文件 demo.py
import numpy as np
a = np.arange(12).reshape(3,4)
print(a)
java調用python程序並輸出該結果
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Process proc;
try {
proc = Runtime.getRuntime().exec("python D:\\demo.py");// 執行py文件
//用輸入輸出流來截取結果
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
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();
}
}
}
如若向python程序中函數傳遞參數並執行出結果,下面就舉一例來說明一下。
同樣建立python腳本文件demo2.py
import sys
def func(a,b):
return (a+b)
if __name__ == '__main__':
a = []
for i in range(1, len(sys.argv)):
a.append((int(sys.argv[i])))
print(func(a[0],a[1]))
其中sys.argv用於獲取參數url1,url2等。而sys.argv[0]代表python程序名,所以列表從1開始讀取參數。
以上代碼實現一個兩個數做加法的程序,下面看看在java中怎麼傳遞函數參數,代碼如下:
int a = 18;
int b = 23;
try {
String[] args = new String[] { "python", "D:\\demo2.py", String.valueOf(a), String.valueOf(b) };
Process proc = Runtime.getRuntime().exec(args);// 執行py文件
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
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();
}
其中args是String[] { “python”,path,url1,url2 }; ,path是python程序所在的路徑,url1是參數1,url2是參數2,以此類推。
2. 將python腳本寫成進程爲java提供服務
在java應用程序中調用python進程提供的服務。這種方法我認爲是最好的!強推!!!python語言寫得程序畢竟還是在python環境中執行最有效率。而且python應用和java應用可以運行在不同的服務器上,通過進程的遠程訪問調用。更讚的是python運行環境還可以是虛擬環境,運行tensorflow模型神馬的完全沒問題!
python腳本文件如下:
import socket
import sys
import threading
import numpy as np
from PIL import Image
def main():
# 創建服務器套接字
serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 獲取本地主機名稱
host = socket.gethostname()
# 設置一個端口
port = 12345
# 將套接字與本地主機和端口綁定
serversocket.bind((host,port))
# 設置監聽最大連接數
serversocket.listen(5)
# 獲取本地服務器的連接信息
myaddr = serversocket.getsockname()
print("服務器地址:%s"%str(myaddr))
# 循環等待接受客戶端信息
while True:
# 獲取一個客戶端連接
clientsocket,addr = serversocket.accept()
print("連接地址:%s" % str(addr))
try:
t = ServerThreading(clientsocket)#爲每一個請求開啓一個處理線程
t.start()
pass
except Exception as identifier:
print(identifier)
pass
pass
serversocket.close()
pass
class ServerThreading(threading.Thread):
# words = text2vec.load_lexicon()
def __init__(self,clientsocket,recvsize=1024*1024,encoding="utf-8"):
threading.Thread.__init__(self)
self._socket = clientsocket
self._recvsize = recvsize
self._encoding = encoding
pass
def run(self):
print("開啓線程.....")
try:
#接受數據
msg = ''
while True:
# 讀取recvsize個字節
rec = self._socket.recv(self._recvsize)
# 解碼
msg += rec.decode(self._encoding)
# 文本接受是否完畢,因爲python socket不能自己判斷接收數據是否完畢,
# 所以需要自定義協議標誌數據接受完畢
if msg.strip().endswith('over'):
msg=msg[:-4]
break
sendmsg = Image.open(msg)
# 發送數據
self._socket.send(("%s"%sendmsg).encode(self._encoding))
pass
except Exception as identifier:
self._socket.send("500".encode(self._encoding))
print(identifier)
pass
finally:
self._socket.close()
print("任務結束.....")
pass
def __del__(self):
pass
if __name__ == "__main__":
main()
在java代碼中訪問python進程的代碼:
package hello;
import java.lang.System;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.InputStream;
public class hello {
public static void main(String[] args){
//System.out.println("Hello World!");
// TODO Auto-generated method stub
try {
InetAddress addr = InetAddress.getLocalHost();
String host=addr.getHostName();
//String ip=addr.getHostAddress().toString(); //獲取本機ip
//log.info("調用遠程接口:host=>"+ip+",port=>"+12345);
// 初始化套接字,設置訪問服務的主機和進程端口號,HOST是訪問python進程的主機名稱,可以是IP地址或者域名,PORT是python進程綁定的端口號
Socket socket = new Socket(host,12345);
// 獲取輸出流對象
OutputStream os = socket.getOutputStream();
PrintStream out = new PrintStream(os);
// 發送內容
out.print( "F:\\xxx\\0000.jpg");
// 告訴服務進程,內容發送完畢,可以開始處理
out.print("over");
// 獲取服務進程的輸入流
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
String tmp = null;
StringBuilder sb = new StringBuilder();
// 讀取內容
while((tmp=br.readLine())!=null)
sb.append(tmp).append('\n');
System.out.print(sb);
// 解析結果
//JSONArray res = JSON.parseArray(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {if(socket!=null) socket.close();} catch (IOException e) {}
System.out.print("遠程接口調用結束.");
}
}
}
[參考鏈接]
https://blog.csdn.net/IT_xiao_bai/article/details/79074988
https://www.cnblogs.com/maosonglin/p/9397257.html
作者:有事沒事扯扯淡
鏈接:https://www.jianshu.com/p/c5e88f9880d3
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。