常见的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 ExecuteCmd {
    /** 执行外部程序,并获取标准输出 */
    public static String execute(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[0]);// 设置编码方式
            } 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("\n");
            }

            bReader.close();
            p.destroy();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

class InputStreamRunnable implements Runnable {
    BufferedReader bReader = null;

    public InputStreamRunnable(InputStream is, String _type) {
        try {
            bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), "UTF-8"));
        } catch (Exception ex) {      ex.printStackTrace();
        }
    }

    public void run() {
        String line;
        int num = 0;
        try {
            while ((line = bReader.readLine()) != null) {
                System.out.println("---->"+String.format("%02d",num++)+" "+line);
            }
            bReader.close();
        } catch (Exception ex) {      ex.printStackTrace();
        }
    }
}

使用时直接调用该工具类即可。

用Java执行Python:Jython踩坑笔记的更多相关文章

  1. CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记

    CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记 cas服务器的搭建 导出证书(1和2步骤是找了课程,随便写了一下存记录,不过对于自己测试不投入使用应该不影响) C:\Users\D ...

  2. EntityFramework CodeFirst SQLServer转Oracle踩坑笔记

    接着在Oracle中使用Entity Framework 6 CodeFirst这篇博文,正在将项目从SQLServer 2012转至Oracle 11g,目前为止遇到的问题在此记录下. SQL Se ...

  3. 避坑手册 | JAVA编码中容易踩坑的十大陷阱

    JAVA编码中存在一些容易被人忽视的陷阱,稍不留神可能就会跌落其中,给项目的稳定运行埋下隐患.此外,这些陷阱也是面试的时候面试官比较喜欢问的问题. 本文对这些陷阱进行了统一的整理,让你知道应该如何避免 ...

  4. ES踩坑笔记

    现在开始在业务上使用ES,记录一些踩坑经历,做点笔记. 2018-11-13 source不返回问题 使用了角色校验,客户端插入成功之后获取数据没有source,和查询参数无关. 检查mapping, ...

  5. Windows+Apache+Python+Django 踩坑记录

    摘要 使用Python进行Web项目开发:相对于主流三大Web端解决方案(Java/.NET/PHP) Python在某些方面具有一定的优势,相对 Java/.NET 有更轻量级的部署方案,相对PHP ...

  6. Vue3.x+element-plus+ts踩坑笔记

    闲聊 前段时间小颖在B站找了个学习vue3+TS的视频,自己尝试着搭建了一些基础代码,在实现功能的过程中遇到了一些问题,为了防止自己遗忘,写个随笔记录一下嘻嘻 项目代码 git地址:vue3.x-ts ...

  7. 微信小程序使用pako.js的踩坑笔记

    问题 今天组长跟我们讨论了个问题,说是文章存储占用有点大,消耗宽带流量费,让我看看能不能找个方法解决一下(文章存储的是html字符串).第一反应是没什么头绪,能想到的就是将相同的字符串替换成一个标识之 ...

  8. clickhouse源码Redhat系列机单机版安装踩坑笔记

    前情概要 由于工作需要用到clickhouse, 这里暂不介绍概念,应用场景,谷歌,百度一大把. 将安装过程踩下的坑记录下来备用 ClickHouse源码 git clone安装(直接下载源码包安装失 ...

  9. 可运行的Java RMI示例和踩坑总结

    简述 资料参考: https://docs.oracle.com/javase/tutorial/rmi/overview.html https://blog.csdn.net/bigtree_372 ...

随机推荐

  1. 读JP摩根的《加密货币展望》阅读笔记

    加密货币不可能死掉, 非常容易以各种形式生存下去早期加密货币的半数以上交易额是地下钱庄交易. 现在已经被投资和投机交易取代.加密货币不可能取代政府发行的货币,其影响到了美元人民币的主权利益加密货币面临 ...

  2. Uvision4创建工程

    创建工程 创建好工程会出现如下的界面 创建文件( .asm 或 .c ) 选择菜单栏中的File->New- 按 Ctrl+S 保存文件并填写文件名 添加到之前创建的工程中 选择Target1- ...

  3. c/c++ 线性表之单向循环链表

    c/c++ 线性表之单向循环链表 线性表之单向循环链表 不是存放在连续的内存空间,链表中的每个节点的next都指向下一个节点,最后一个节点的下一个节点不是NULL,而是头节点.因为头尾相连,所以叫单向 ...

  4. CentOS6.5 安装并配置vsftpd

    一.获取root权限 su 输入root密码 二.检查是否安装 rpm -qa | grep vsftpd 如果安装,会显示安装版本号,没有就什么都不显示 三.若已安装过vsftpd,先卸载.卸载前, ...

  5. Lingo求解线性规划案例4——下料问题

    凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 造纸厂接到定单,所需卷纸的宽度和长度如表 卷纸的宽度 长度 5 7 9 10000 30000 20000 工 ...

  6. Lingo求解线性规划案例3——混料问题

    凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/  某糖果厂用原料A.B和C按不向比率混合加工而成甲.乙.丙三种糖果(假设混合加工中不损耗原料).原料A.B.C ...

  7. 【项目 · Wonderland】会议一 · 可达鸭

    [软件工程实践 · 团队项目] 第一次作业 Part 0 · 简 要 目 录 Part 1 · 队 伍 阵 容 Part 2 · 会 议 记 录 相 关 Part 3 · 会 议 讨 论 记 录 Pa ...

  8. Word中的通配符随意组合进行批量替换或删除某些内容

    长文档需要批量修改或删除某些内容的时候,我们可以利用Word中的通配符来搞定这一切,当然,前提是你必须会使用它.通配符的功能非常强大,能够随意组合替换或删除我们定义的规则内容,下面易老师就分享一些关于 ...

  9. scp 实现文件打包上传到linux

    在A服务器上将/root/lk目录下所有的文件传输到B的/home/lk/cpfile目录下,命令为: scp -r /root/lk root@43.224.34.73:/home/lk/cpfil ...

  10. pom文件miss artifact com.sun:tools:jar:1.5.0:system问题

    问题现象: 导入新的maven项目时,有时候pom.xml文件会提示一个错误信息:Missing artifact com.sun:tools:jar:1.5.0:system 问题原因: maven ...