Java代码中调用shell脚本和python脚本并获得输出结果(分为小数据量和大数据量)

本文介绍了如何在Java代码中调用shell和python脚本,并获取输出结果。当脚本输出结果较大时,会出现waitFor阻塞问题。解决方案是通过新开线程实时清理输入流缓冲区,实现输出与读取同步,确保程序正常运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java代码中调用shell和python脚本有多种实现方式,通用方式是使用java.lang中的Runtime类新开进程,调用python脚本的一个例子如下(shell同理):

public String python(String pythonPath, String[] params) {
        File file = new File(pythonPath);
        if (!file.exists()){
            return "python脚本不存在!";
        }

        String[] command = Arrays.copyOf(new String[]{"python", pythonPath}, params.length + 2);
        System.arraycopy(params, 0, command, 2, params.length);

        List res = new ArrayList<>();
        try {
            Process process = Runtime.getRuntime().exec(command, null, null);
            process.waitFor();

            Scanner scanner = new Scanner(process.getInputStream());
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                res.add(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return "success";
    }

例子中,参数pythonPath就是python脚本的绝对路径,参数params是脚本的参数数组,command就是执行python命令字符串数组,格式就是python + 脚本 + 参数,构造好command后传入exec()中执行新进程,然后调用waitFor()函数等待进程结束,结束后从进程的输入流中获得脚本的输出结果存储到字符串数组中。

乍一看,上面的代码并没有问题,对于少量的输出结果执行后相当完美,但是当脚本的输出结果大小大于inputStream缓冲区大小时,程序会阻塞在waitFor()函数这里,问题就在于脚本的输出结果是在进程执行完之后才读取,一个好的解决办法就是新开一个清理线程来不断清空缓冲区,也就是输出和读取同时进行,代码如下:

    public String python(String pythonPath, String[] params) {
        File file = new File(pythonPath);
        if (!file.exists()){
            return "python脚本不存在!";
        }

        String[] command = Arrays.copyOf(new String[]{"python", pythonPath}, params.length + 2);
        System.arraycopy(params, 0, command, 2, params.length);

        List res = new ArrayList<>();
        try {
            Process process = Runtime.getRuntime().exec(command, null, null);
            
            ClearThread ct = new ClearThread(process);
            ct.start();
            
            process.waitFor();
            Thread.sleep(1000);
            
            ct.setEnd(true);
            res = ct.getRes();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return "success";
    }

    class ClearThread extends Thread {
        Process process;
        boolean end;
        List res;

        public ClearThread(Process process) {
            this.process = process;
            end = false;
            res = new ArrayList<>();
        }

        @Override
        public void run() {
            if (process == null) {
                return;
            }
            
            Scanner scanner = new Scanner(process.getInputStream());
            while (process != null && !end) {
                while (scanner.hasNextLine()) {
                    String line = scanner.nextLine();
                    res.add(line);
                }
            }
        }

        public void setEnd(boolean end) {
            this.end = end;
        }

        public List getRes() {
            return res;
        }
    }
其中,在脚本执行执行完后调用sleep()让主线程睡眠一秒,否则会导致清理线程可能会还没拿到缓冲区数据就被end标识符结束了(可以用小数据试验一下)。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值