java調(diào)用python方法

最近做了一個(gè)東西,需要在java應(yīng)用調(diào)用python的函數(shù)。查了網(wǎng)上若干資料,有很多種方法(直接用Jython,etc.),親測(cè)兩種最有效的方法在此分享一下。

1.使用Runtime.getRuntime()執(zhí)行腳本文件

該方法可以運(yùn)行含有python第三方庫(kù)的程序

先建立python腳本文件 demo.py

import numpy as np

a = np.arange(12).reshape(3,4)
print(a)

java調(diào)用python程序并輸出該結(jié)果

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");// 執(zhí)行py文件
            //用輸入輸出流來(lái)截取結(jié)果
            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程序中函數(shù)傳遞參數(shù)并執(zhí)行出結(jié)果,下面就舉一例來(lái)說(shuō)明一下。
同樣建立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用于獲取參數(shù)url1,url2等。而sys.argv[0]代表python程序名,所以列表從1開(kāi)始讀取參數(shù)。
以上代碼實(shí)現(xiàn)一個(gè)兩個(gè)數(shù)做加法的程序,下面看看在java中怎么傳遞函數(shù)參數(shù),代碼如下:

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);// 執(zhí)行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是參數(shù)1,url2是參數(shù)2,以此類推。

2. 將python腳本寫(xiě)成進(jìn)程為java提供服務(wù)

在java應(yīng)用程序中調(diào)用python進(jìn)程提供的服務(wù)。這種方法我認(rèn)為是最好的!強(qiáng)推!??!python語(yǔ)言寫(xiě)得程序畢竟還是在python環(huán)境中執(zhí)行最有效率。而且python應(yīng)用和java應(yīng)用可以運(yùn)行在不同的服務(wù)器上,通過(guò)進(jìn)程的遠(yuǎn)程訪問(wèn)調(diào)用。更贊的是python運(yùn)行環(huán)境還可以是虛擬環(huán)境,運(yùn)行tensorflow模型神馬的完全沒(méi)問(wèn)題!

python腳本文件如下:

import socket
import sys
import threading
import numpy as np
from PIL import Image

def main():
    # 創(chuàng)建服務(wù)器套接字
    serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 獲取本地主機(jī)名稱
    host = socket.gethostname()
    # 設(shè)置一個(gè)端口
    port = 12345
    # 將套接字與本地主機(jī)和端口綁定
    serversocket.bind((host,port))
    # 設(shè)置監(jiān)聽(tīng)最大連接數(shù)
    serversocket.listen(5)
    # 獲取本地服務(wù)器的連接信息
    myaddr = serversocket.getsockname()
    print("服務(wù)器地址:%s"%str(myaddr))
    # 循環(huán)等待接受客戶端信息
    while True:
        # 獲取一個(gè)客戶端連接
        clientsocket,addr = serversocket.accept()
        print("連接地址:%s" % str(addr))
        try:
            t = ServerThreading(clientsocket)#為每一個(gè)請(qǐng)求開(kāi)啟一個(gè)處理線程
            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("開(kāi)啟線程.....")
        try:
            #接受數(shù)據(jù)
            msg = ''
            while True:
                # 讀取recvsize個(gè)字節(jié)
                rec = self._socket.recv(self._recvsize)
                # 解碼
                msg += rec.decode(self._encoding)
                # 文本接受是否完畢,因?yàn)閜ython socket不能自己判斷接收數(shù)據(jù)是否完畢,
                # 所以需要自定義協(xié)議標(biāo)志數(shù)據(jù)接受完畢
                if msg.strip().endswith('over'):
                    msg=msg[:-4]
                    break
           
            sendmsg = Image.open(msg)
            # 發(fā)送數(shù)據(jù)
            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("任務(wù)結(jié)束.....")
        
        pass

    def __del__(self):
        pass

if __name__ == "__main__":
    main()

在java代碼中訪問(wèn)python進(jìn)程的代碼:

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(); //獲取本機(jī)ip
            //log.info("調(diào)用遠(yuǎn)程接口:host=>"+ip+",port=>"+12345);

            // 初始化套接字,設(shè)置訪問(wèn)服務(wù)的主機(jī)和進(jìn)程端口號(hào),HOST是訪問(wèn)python進(jìn)程的主機(jī)名稱,可以是IP地址或者域名,PORT是python進(jìn)程綁定的端口號(hào)
            Socket socket = new Socket(host,12345);

            // 獲取輸出流對(duì)象
            OutputStream os = socket.getOutputStream();
            PrintStream out = new PrintStream(os);
            // 發(fā)送內(nèi)容
            out.print( "F:\\xxx\\0000.jpg");
            // 告訴服務(wù)進(jìn)程,內(nèi)容發(fā)送完畢,可以開(kāi)始處理
            out.print("over");

            // 獲取服務(wù)進(jìn)程的輸入流
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
            String tmp = null;
            StringBuilder sb = new StringBuilder();
            // 讀取內(nèi)容
            while((tmp=br.readLine())!=null)
                sb.append(tmp).append('\n');
            System.out.print(sb);
            // 解析結(jié)果
            //JSONArray res = JSON.parseArray(sb.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {if(socket!=null) socket.close();} catch (IOException e) {}
            System.out.print("遠(yuǎn)程接口調(diào)用結(jié)束.");
        }
      }
}

[參考鏈接]
https://blog.csdn.net/IT_xiao_bai/article/details/79074988
https://www.cnblogs.com/maosonglin/p/9397257.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容