用Java執行Python:Jython踩坑筆記
常見的java呼叫python指令碼方式
1.通過Jython.jar提供的類庫實現
2.通過Runtime.getRuntime()開啟程式來執行指令碼檔案
1.Jython
Jpython使用時,版本很重要!大多數坑來源於此。這句話不聽的人還得走點彎路
執行環境:Python2.7 + Jython-standalone-2.7.0
<!--Maven依賴,jar包自行前往倉庫下載-->
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.7.0</version>
</dependency>
1)Jython執行Python語句
import org.python.util.PythonInterpreter;
public class HelloPython {
public static void main(String[] args) {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("print(`hello`)");
}
}
2)Jython執行Python指令碼
import org.python.util.PythonInterpreter;
public class HelloPython {
public static void main(String[] args) {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile("./pythonSrc/time.py");
}
}
3)Jython執行Python方法獲取返回值
PythonInterpreter interpreter = new PythonInterpreter();
interpreter = new PythonInterpreter();
interpreter.execfile("./pythonSrc/fibo.py");
PyFunction function = (PyFunction)interpreter.get("fib",PyFunction.class);
PyObject o = function.__call__(new PyInteger(8));
System.out.println(o.toString());
fibo.py
# Fibonacci numbers module
def fib(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b ·
return result
2.Jython的侷限
Jython在執行普通py指令碼時速度很慢,而且在含有第三方庫(requests, jieba…)時bug很多,不易處理。 原因在於,python執行時的sys.path和Jython的sys.path路徑不一致,以及Jython的處理不是很好。
python執行時:
[`F:\Eclipse for Java EE\workspace\Jython\pythonSrc`, `F:\Python27\DLLs`, `F:\Python27\lib`, `F:\Python27\lib\lib-tk`, `F:\Python27`, `F:\Python27\lib\site-packages`, `F:\Python27\lib\site-packages\unknown-0.0.0-py2.7.egg`, `F:\Python27\lib\site-packages\requests-2.18.4-py2.7.egg`, `F:\Python27\lib\site-packages\certifi-2018.1.18-py2.7.egg`, `F:\Python27\lib\site-packages\urllib3-1.22-py2.7.egg`, `F:\Python27\lib\site-packages\idna-2.6-py2.7.egg`, `F:\Python27\lib\site-packages\chardet-3.0.4-py2.7.egg`, `C:\windows\system32\python27.zip`, `F:\Python27\lib\plat-win`]
Jython 執行時:
[`F:\Maven\repo\org\python\jython-standalone\2.7.0\Lib`, `F:\Maven\repo\org\python\jython-standalone\2.7.0\jython-standalone-2.7.0.jar\Lib`, `__classpath__`, `__pyclasspath__/`]
關於路徑問題,我們有兩種解決方法,一是手動新增第三方庫路徑,呼叫
PySystemState sys = Py.getSystemState();
System.out.println(sys.path.toString());
sys.path.add("F:\Python27\Lib\site-packages\jieba");
二是把第三方庫資料夾放到執行的.py指令碼同級目錄。
然後新的問題來了,你以為路徑是最終的問題嗎?不止,也許是Python的版本語法問題,2x,3x,導致你在用Jython執行含第三方庫的.py指令碼時,各種Module不存在。原本博主走的Jython的路子,還下載了jieba第三方庫,後來執行時一大堆錯誤:jieba庫好像對py3有過渡支援,jython不支援這種語法格式,我改了jieba一處又一處,所以,博主在受過摧殘之後果斷放棄Jython!因為不能使用第三方庫的python,然並卵!
最終方法來了:模擬控制檯執行
public class Cmd {
public static void main(String[] args) throws IOException, InterruptedException {
String[] arguments = new String[] { "python", "./pythonSrc/time.py", "huzhiwei", "25" };
try {
Process process = Runtime.getRuntime().exec(arguments);
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
int re = process.waitFor();
System.out.println(re);
} catch (Exception e) {
e.printStackTrace();
}
}
}
time.py
#!/usr/bin/python
#coding=utf-8
#定義一個方法
def my_test(name, age):
print("name: "+str(name))
print(age) #str()防解碼出錯
return "success"
#主程式
#sys.argv[1]獲取cmd輸入的引數
my_test(sys.argv[1], sys.argv[2])
執行結果
name: huzhiwei
25
0
再嘮兩塊錢的~
這個方法的侷限性也來了,對python開發人員很簡單,直接列印輸出,但一個python模組只能做一件事,這點很像Python端給Java端的一個公開介面,類似Servlet吧?好處也有,不會出錯,執行快!還在猶豫的同學趕快轉cmd吧~!
2018-4-19:
博主在模擬cmd呼叫Python時遇到一些情況,這類問題可以歸類為“超時,阻塞”等
問題原因:
Process p=Runtime.getRuntime().exec(String[] cmd);
Runtime.exec方法將產生一個本地的程式,並返回一個Process子類的例項,該例項可用於控制程式或取得程式的相關資訊。
由於呼叫Runtime.exec方法所建立的子程式沒有自己的終端或控制檯,因此該子程式的標準IO(如stdin,stdou,stderr)都通過
p.getOutputStream(),
p.getInputStream(),
p.getErrorStream()
方法重定向給它的父程式了.使用者需要用這些stream來向 子程式輸入資料或獲取子程式的輸出。
例如:Runtime.getRuntime().exec("ls")
另外需要關心的是Runtime.getRuntime().exec()中產生停滯(阻塞,blocking)的問題?
這個是因為Runtime.getRuntime().exec()要自己去處理stdout和stderr的輸出,
就是說,執行的結果不知道是現有錯誤輸出(stderr),還是現有標準輸出(stdout)。
你無法判斷到底那個先輸出,所以可能無法讀取輸出,而一直阻塞。
例如:你先處理標準輸出(stdout),但是處理的結果是先有錯誤輸出(stderr),
一直在等錯誤輸出(stderr)被取走了,才到標準輸出(stdout),這樣就產生了阻塞。
解決辦法:
用兩個執行緒將標準輸出(stdout)和錯誤輸出(stderr)。
完整程式碼:
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Created by yster@foxmail.com 2018年4月19日 下午1:50:06
*/
public class ExcuteCmd {
/** 執行外部程式,並獲取標準輸出 */
public static String excuteCmd_multiThread(String[] cmd, String encoding) {
BufferedReader bReader = null;
InputStreamReader sReader = null;
try {
Process p = Runtime.getRuntime().exec(cmd);
/* 為"錯誤輸出流"單獨開一個執行緒讀取之,否則會造成標準輸出流的阻塞 */
Thread t = new Thread(new InputStreamRunnable(p.getErrorStream(), "ErrorStream"));
t.start();
/* "標準輸出流"就在當前方法中讀取 */
BufferedInputStream bis = new BufferedInputStream(p.getInputStream());
if (encoding != null && encoding.length() != 0) {
sReader = new InputStreamReader(bis, encoding);// 設定編碼方式
} else {
sReader = new InputStreamReader(bis, "utf-8");
}
bReader = new BufferedReader(sReader);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bReader.readLine()) != null) {
sb.append(line);
sb.append("
");
}
bReader.close();
p.destroy();
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return "result: error";
} finally {
}
}
}
class InputStreamRunnable implements Runnable {
BufferedReader bReader = null;
String type = null;
public InputStreamRunnable(InputStream is, String _type) {
try {
bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), "UTF-8"));
type = _type;
} catch (Exception ex) {
}
}
@SuppressWarnings("unused")
public void run() {
String line;
int lineNum = 0;
try {
while ((line = bReader.readLine()) != null) {
lineNum++;
// Thread.sleep(200);
}
bReader.close();
} catch (Exception ex) {
}
}
}
使用時直接呼叫該工具類即可。
相關文章
- DelayedWorkQueue踩坑筆記筆記
- Realm ios踩坑筆記iOS筆記
- MUI的踩坑筆記UI筆記
- Go踩坑筆記(十九)Go筆記
- 筆記:Mysql踩坑之路筆記MySql
- vue + typescript 踩坑筆記(一)VueTypeScript筆記
- next.js 踩坑筆記JS筆記
- vue + typescript 踩坑筆記(二)VueTypeScript筆記
- Vue踩坑筆記(更新ing)Vue筆記
- Android、Java RSA加密踩坑記AndroidJava加密
- Node系列-爬蟲踩坑筆記爬蟲筆記
- 筆記:Node.js Postgresql踩坑筆記Node.jsSQL
- Java多執行緒筆記Java執行緒筆記
- Windows+Apache+Python+Django 踩坑記錄WindowsApachePythonDjango
- Java踩坑記系列之Arrays.AsListJava
- Python筆記二之多執行緒Python筆記執行緒
- 【踩坑筆記】專案出現Permission denied筆記
- Python學習筆記|Python之執行緒Python筆記執行緒
- removeChild踩坑記REM
- vue 踩坑記Vue
- mpVue 踩坑記Vue
- vuepress踩坑記Vue
- 【踩坑指南】執行緒池使用不當的五個坑執行緒
- Python學習筆記 - 多執行緒Python筆記執行緒
- 筆記:Python的兩種執行模式筆記Python模式
- java核心技術筆記--執行緒Java筆記執行緒
- Java 多執行緒學習筆記Java執行緒筆記
- mpvue開發微信小程式踩坑筆記Vue微信小程式筆記
- 前端專案框架搭建隨筆---Webpack踩坑記前端框架Web
- java併發筆記之java執行緒模型Java筆記執行緒模型
- Jenkins踩坑之旅:nohup後臺執行shell命令Jenkins
- Sentry 部署踩坑記
- RN 踩坑:雜記
- sealos踩坑記錄
- strtotime 踩坑記錄
- Dubbo 2.7.1 踩坑記
- DietPi踩坑記錄
- laravel踩坑記錄Laravel