1. 程式人生 > >Java呼叫Python程式方法總結(最全最詳細)

Java呼叫Python程式方法總結(最全最詳細)

如何使用Java呼叫Python程式

 

 

 

本文為大家介紹如何java呼叫python方法,供大家參考。 
實際工程專案中可能會用到Java和python兩種語言結合進行,這樣就會涉及到一個問題,就是怎麼用Java程式來呼叫已經寫好的python指令碼呢,一共有三種方法可以實現,具體方法分別為大家介紹:

 

1. 在java類中直接執行python語句

此方法需要引用 org.python包,需要下載Jpython。在這裡先介紹一下Jpython。下面引入百科的解釋:

  • Jython是一種完整的語言,而不是一個Java翻譯器或僅僅是一個Python編譯器,它是一個Python語言在Java中的完全實現。Jython也有很多從CPython中繼承的模組庫。最有趣的事情是Jython不像CPython或其他任何高階語言,它提供了對其實現語言的一切存取。所以Jython不僅給你提供了Python的庫,同時也提供了所有的Java類。這使其有一個巨大的資源庫。

 

這裡我建議下載最新版本的Jpython,因為可以使用的python函式庫會比老版本的多些,目前最新版本為2.7。 
下載jar包請點選Download Jython 2.7.0 - Standalone Jar 
下載安裝程式請點選Download Jython 2.7.0 - Installer 
如果使用maven依賴新增的話,使用下面的語句

 
  1. <dependency>

  2. <groupId>org.python</groupId>

  3. <artifactId>jython-standalone</artifactId>

  4. <version>2.7.0</version>

  5. </dependency>

以上準備好了,就可以直接在java類中寫python語句了,具體程式碼如下:

 
  1. PythonInterpreter interpreter = new PythonInterpreter();

  2. interpreter.exec("a=[5,2,3,9,4,0]; ");

  3. interpreter.exec("print(sorted(a));"); //此處python語句是3.x版本的語法

  4. interpreter.exec("print sorted(a);"); //此處是python語句是2.x版本的語法

 

輸出結果如下:

這裡會看到輸出的結果都是一樣的,也就是說Jpython相容python2.x和3.x版本的語句,執行速度會比直接執行python程式稍慢一點。 
但是每次執行結果都會提示console: Failed to install ”: java.nio.charset.UnsupportedCharsetException: cp0. 這樣看起來很煩,因為每次執行結果都會出現紅色的提示語句,以為是錯誤,程式設計師應該都不願意看到這一幕,得想個辦法解決。 
解決方法如下: 
在要執行的程式碼上右鍵, Run As>Run Configurations,選擇第二個頁籤Arguments,在VM arguments中新增以下語句 
-Dpython.console.encoding=UTF-8 
然後Apply->Run就可以了。

如下圖所示:

 

 

 

2. 在java中呼叫本地python指令碼

 

 

首先在本地建立一個python指令碼,命名為add.py,寫了一個簡單的兩個數做加法的函式,程式碼如下:

 
  1. def add(a,b):

  2. return a + b

 

python的功能函式已經寫好,接下來我們寫一個java的測試類(同樣需要用到Jpython包),來測試一下是否可以執行成功。程式碼如下:

 
  1. import org.python.core.PyFunction;

  2. import org.python.core.PyInteger;

  3. import org.python.core.PyObject;

  4. import org.python.util.PythonInterpreter;

  5.  
  6. public class Java_Python_test {

  7.  
  8. public static void main(String[] args) {

  9. // TODO Auto-generated method stub

  10. PythonInterpreter interpreter = new PythonInterpreter();

  11. interpreter.execfile("D:\\add.py");

  12.  
  13. // 第一個引數為期望獲得的函式(變數)的名字,第二個引數為期望返回的物件型別

  14. PyFunction pyFunction = interpreter.get("add", PyFunction.class);

  15. int a = 5, b = 10;

  16. //呼叫函式,如果函式需要引數,在Java中必須先將引數轉化為對應的“Python型別”

  17. PyObject pyobj = pyFunction.__call__(new PyInteger(a), new PyInteger(b));

  18. System.out.println("the anwser is: " + pyobj);

  19. }

  20. }

 

執行結果如圖所示:

OK,測試成功了~

關於Jpython更多詳細的資訊可以參考官方的相關文件,官網地址點這裡

 

 

注意:以上兩個方法雖然都可以呼叫python程式,但是使用Jpython呼叫的python庫不是很多,如果你用以上兩個方法呼叫,而python的程式中使用到第三方庫,這時就會報錯java ImportError: No module named xxx。遇到這種情況推薦使用下面的方法,即可解決該問題。

3. 使用Runtime.getRuntime()執行指令碼檔案(推薦)

 

 

為了驗證該方法可以執行含有python第三方庫的程式,我們先寫一個簡單的python指令碼,程式碼如下:

 
  1. import numpy as np

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

  4. print(a)

 

 

可以看到程式中用到了numpy第三方庫,並初始化了一個3×4的一個矩陣。 
下面來看看怎麼用Runtime.getRuntime()方法來呼叫python程式並輸出該結果,java程式碼如下:

 
  1. import java.io.BufferedReader;

  2. import java.io.IOException;

  3. import java.io.InputStreamReader;

  4.  
  5. public class Demo1 {

  6.  
  7. public static void main(String[] args) {

  8. // TODO Auto-generated method stub

  9. Process proc;

  10. try {

  11. proc = Runtime.getRuntime().exec("python D:\\demo1.py");// 執行py檔案

  12. //用輸入輸出流來擷取結果

  13. BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

  14. String line = null;

  15. while ((line = in.readLine()) != null) {

  16. System.out.println(line);

  17. }

  18. in.close();

  19. proc.waitFor();

  20. } catch (IOException e) {

  21. e.printStackTrace();

  22. } catch (InterruptedException e) {

  23. e.printStackTrace();

  24. }

  25. }

  26. }

 

 

輸出的結果如下圖所示:

 

 

可以看到執行成功了,但有的朋友可能會問了,怎麼在python程式中函式傳遞引數並執行出結果,下面我就舉一例來說明一下。 
先寫一個python的程式,程式碼如下:

 
  1. import sys

  2.  
  3. def func(a,b):

  4. return (a+b)

  5.  
  6. if __name__ == '__main__':

  7. a = []

  8. for i in range(1, len(sys.argv)):

  9. a.append((int(sys.argv[i])))

  10.  
  11. print(func(a[0],a[1]))

 

 

其中sys.argv用於獲取引數url1,url2等。而sys.argv[0]代表python程式名,所以列表從1開始讀取引數。 
以上程式碼實現一個兩個數做加法的程式,下面看看在java中怎麼傳遞函式引數,程式碼如下:

 
  1. int a = 18;

  2. int b = 23;

  3. try {

  4. String[] args = new String[] { "python", "D:\\demo2.py", String.valueOf(a), String.valueOf(b) };

  5. Process proc = Runtime.getRuntime().exec(args1);// 執行py檔案

  6.  
  7. BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

  8. String line = null;

  9. while ((line = in.readLine()) != null) {

  10. System.out.println(line);

  11. }

  12. in.close();

  13. proc.waitFor();

  14. } catch (IOException e) {

  15. e.printStackTrace();

  16. } catch (InterruptedException e) {

  17. e.printStackTrace();

  18. }

 

 

其中args是String[] { “python”,path,url1,url2 }; ,path是python程式所在的路徑,url1是引數1,url2是引數2,以此類推。 
最後結果如圖所示:

 

 


OK,成功了。

 

 

 

最後補充一點:

本人電腦上由於同時存在兩個python,而我不想用預設的那個,也不想修改預設的python直譯器,這種情況下,可以寫一個bat檔案,在bat檔案中通過dos命令切換到該python所在目錄,然後執行py檔案(py檔案要放在該目錄下)

下面附上程式:

bat檔案:

 
  1. @echo off

  2. C:

  3. cd C:\Anaconda2\envs\py3

  4. start python test.py

  5. exit

java程式:

 
  1. import java.io.BufferedReader;

  2. import java.io.IOException;

  3. import java.io.InputStreamReader;

  4.  
  5. public class Demo1 {

  6.  
  7. public static void main(String[] args) {

  8. // TODO Auto-generated method stub

  9. Process proc;

  10. try {

  11. proc = Runtime.getRuntime().exec("cmd /c E:\\Faultdetection\\fault1\\run.bat");// 執行py檔案

  12. //用輸入輸出流來擷取結果

  13. BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

  14. String line = null;

  15. while ((line = in.readLine()) != null) {

  16. System.out.println(line);

  17. }

  18. in.close();

  19. proc.waitFor();

  20. } catch (IOException e) {

  21. e.printStackTrace();

  22. } catch (InterruptedException e) {

  23. e.printStackTrace();

  24. }

  25. }