java执行python脚本

python执行是由多种方式的,可以在java程序中编写python代码执行,也可以提前写脚本,通过执行脚本文件方式执行。由于个人需求,脚本内容动态变化,不适合写在代码中,故,介绍执行脚本的方式:

话不多说,上代码

通过java执行脚本文件,

关键代码(执行脚本的)

Runtime.getRuntime().exec(String[] args)

注意事项

args[0]是python执行的命令,windows和linux注意区分,args[1]是文件地址,是本地的地址噢,不是http网络文件。

下面是执行代码:

public class ScriptUtils {

    private static Logger logger = LoggerFactory.getLogger(ScriptUtils.class);

    /**
     * 执行python脚本
     * @param path 文件地址:比如 D:\\xxx\\helloWorld.py
     */
    public static Boolean exePython(String path){
        logger.info("======python start");

        boolean success = false;
        Process proc = null;
        try {
            // linux 用 "python3", windows 用python.exe的绝对路径("D:\\xxx\\Python\\Python39-32\\python.exe")
            String[] args1 = new String[]{"python3", path};
            proc = Runtime.getRuntime().exec(args1);

            // 读写日志线程,分成两个也是为了避免线程堵塞之类的问题,具体原因网络上有很多说明
            Thread thread1 = new Thread(new StreamReaderThread(proc.getInputStream(),"info.txt"));
            Thread thread2 = new Thread(new StreamReaderThread(proc.getErrorStream(),"error.txt"));

            thread2.start();
            //必须后执行,否则正确消息容易接收不到
            thread1.start();
            // result是结果,具体有哪些值,可以自己去查一下
            int result = proc.waitFor();
            success = result != -1;

            //等待后台线程读写完毕
            Thread.sleep(1000);

        } catch (Exception e) {
            e.printStackTrace();
            throw new ServerException("python error:" + e);

        } finally {
            try {
                proc.getErrorStream().close();
                proc.getInputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            proc.destroy();
            logger.info("======python end");
        }
        return success;
    }


    /**
     * 执行groovy脚本的(附赠哈哈,都是脚本执行嘛)
     */
    public static Boolean exeGroovy(String path) {
        logger.info("======groovy start");

        boolean success = false;
        try {
            GroovyShell groovyShell = new GroovyShell();
            Object result = groovyShell.evaluate(new File(path));
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServerException("groovy error:" + e);

        } finally {
            logger.info("======groovy end");
        }
        return success;
    }
}

日志输出: 

public class StreamReaderThread implements Runnable {
    private Logger logger = LoggerFactory.getLogger(StreamReaderThread.class);

    /*
     * 输出流
     */
    private InputStream inputStream;
    /*
     * 输出信息保存的文件名称
     */
    private String logName;

    public StreamReaderThread(InputStream inputStream, String logName) {
        this.inputStream = inputStream;
        this.logName = logName;
    }

    /**
     * FileWriter将日志写入某文件
     * 也可以用logger打印日志记录。
     */
    public void run() {
        BufferedReader in = null;
        FileWriter fwriter = null;
        try {
            in = new BufferedReader(new InputStreamReader(this.inputStream, "gbk"));
            fwriter = new FileWriter(logName, true);
            String line = null;
            while ((line = in.readLine()) != null) {
                fwriter.write(line);
                logger.info(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                fwriter.flush();
                fwriter.close();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

如果是网络文件的话,先下载到本机:

/**
 * 下载网络文件到本机
 * @Param urlString 网络文件下载地址:http://xxx.xx.xx
 * @Param fileName  文件名称
 */
public static String downloadFile(String urlString, String fileName) throws IOException {
        makeDir(scriptConfig.getUploadPath());
        String filePath = scriptConfig.getUploadPath() + SnowflakeIdUtils.nextId() + fileName;

        // 构造URL
        URL url = new URL(urlString);
        // 打开连接
        URLConnection con = url.openConnection();

        // 设置Java服务器代理连接,要不然报错403
        // 浏览器可以访问此url图片并显示,但用Java程序就不行报错Server returned HTTP response code:403 for URL
        // 具体原因:服务器的安全设置不接受Java程序作为客户端访问(被屏蔽),解决办法是设置客户端的User Agent
        con.setRequestProperty("User-Agent", "Mozilla/4.0(compatible;MSIE 5.0;Windows NT;DigExt)");

        // 输入流
        InputStream is = con.getInputStream();

        // 1K的数据缓冲
        byte[] bs = new byte[1024];
        // 读取到的数据长度
        int len;
        // 输出的文件流
        OutputStream os = new FileOutputStream(filePath);
        // 开始读取
        while ((len = is.read(bs)) != -1) {
            os.write(bs, 0, len);
        }
        // 完毕,关闭所有链接
        os.close();
        is.close();

        return filePath;
    }

    private static void makeDir(String fileFolder) {
        File file = new File(fileFolder);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdir();
        }
    }

关于项目发布

这里再啰嗦几句吧,在编写python脚本时,我用的是windows环境,项目上线后,是放到linux环境的,通过k8s管理的。当时遇到了一个问题就是k8s环境的镜像是java的,没有集成python,这里注意要自定义一个jdk+python都支持的镜像。(如果python有用到第三方库 也要打包进来噢)

String[] args1 = new String[]{"python3", path};
proc = Runtime.getRuntime().exec(args1);

args1[0]的python3我写到了配置文件里,通过配置读取,这样在windows/linux切换时,只需要加载不同的配置文件就好了。

关于其他方式执行:

maven引入jython其实也是可以执行脚本文件 或者 脚本内容的,并且使用方式非常的简单。没有用这个是因为jython的库是有限的。当使用第三方库或自定义库的时候就有些局限了(我也不知道有没有解决方案,懒得找),所以我还是更倾向于使用Runtime.getRuntime().exec();

jython方法也提供一下吧:

1.pom文件中引用

<dependency>
   <groupId>org.python</groupId>
   <artifactId>jython-standalone</artifactId>
   <version>2.7.0</version>
</dependency>

2. 脚本文件执行

PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile("D:\\xxx\\helloWorld.py");

3.脚本内容执行

PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("a='hello world';");
interpreter.exec("print a;");

4.还有执行指定方法,给python传参的之类的,看参考文献吧,不举例了。

参考文献

(15条消息) Java执行python脚本_为山九仞的博客-CSDN博客_java执行python脚本icon-default.png?t=M7J4https://blog.csdn.net/qq_41665121/article/details/105675360?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-1-105675360-blog-126644076.pc_relevant_multi_platform_whitelistv4eslandingrelevant&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-1-105675360-blog-126644076.pc_relevant_multi_platform_whitelistv4eslandingrelevant&utm_relevant_index=2

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值