Java执行python或者java文件

有一个特殊需求,要求网站在线执行代码。于是就捣鼓了一下:

这个是python的:

首先把源代码生成文件:

private boolean codeToFile() {
    long t = new Date().getTime();
    this.tempFile = this.outDir + "/" + "p" + t + ".py";
    File file = new File(tempFile);
    try {
        if (file.createNewFile()) {
            FileOutputStream f1 = new FileOutputStream(file);//(file,true),这里有true的话,代表可以在文件后面追加内容
            byte[] buff = code.getBytes();//将字符串转换为字节数组
            try {
                f1.write(buff);//把字节数组的内容写进去文件
            } catch (Exception e) {
                // TODO: handle exception
            } finally {
                try {
                    f1.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return false;
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
        log.info(this.tempFile + "创建失败!");
        this.tempFile = "";
        return false;
    }

    return true;
}

然后执行代码,里面的this.temp就是上面这个函数生成的,带路径哦:

public void execPython() throws IOException {
        // log.info("-----输出-----");

        //Runtime run = Runtime.getRuntime();

        BufferedReader in = null;
        BufferedReader err = null;
        // Process p = null;
        //InputStream in = null;
        //BufferedReader br = null;
        try {
            long time = new Date().getTime();
            log.info("将要执行的代码:\n" + this.code);
            
process = Runtime.getRuntime().exec("python.exe " + this.tempFile);
        //特别注意,in是代码的输出,out是输入
            in = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
            err = new BufferedReader(new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8));


            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
            if (!Common.isEmpty(this.testArray)) {
                for (int i = 0; i < testArray.size(); i++) {
                    out.write(testArray.get(i) + "\n");
                }
                out.flush();
                out.close();//关闭流
            } else {
                out.write("24\n48 36 72 108 12 24\n");//输入一些数据,防止等待输入的堵塞
                out.flush();
                out.close();//关闭流
            }



            StringBuffer outputBuffer = new StringBuffer();
            boolean deadLoop = false;

            synchronized (in) {
                in.wait(500);
            }

            //s=br.readLine();
            // 防止没有输出的死循环

            String s;
            if (false) {
                output = "没有输出或出现死循环";
                deadLoop = true;
            } else {
                long now = new Date().getTime();
                while ((s = in.readLine()) != null) {
                    // log.info(lineTxt);
                    log.info("输出结果为:" + s);
                    outputBuffer.append(s);
                    outputBuffer.append("@");

                    // 防止死循环,只能防止有输出的死循环
                    if (outputBuffer.length() >= 2000 || now - time >= 1000 * 60 * 2) {
                        log.error(process.toString());
                        deadLoop = true;
                        break;
                    }
                }
            }

            getSyntaxError(err);
            //out.flush();
            //out.close();//关闭流
            log.info("============result:===============");
            if (!deadLoop) {
                output = outputBuffer.toString().trim();
                output = output.length() > 1 ? output.substring(0, output.length() - 1) : "";
            } else {
                output = "没有输出或出现死循环";
            }
            log.info(output);
            int exitCode = process.waitFor();
            System.out.println("Python脚本执行完毕,退出码: " + exitCode);

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (err != null) err.close();
            if (in != null) in.close();
            if (process != null) {
                process.destroyForcibly();
                process.destroy();

            }


            
log.info("删除临时文件" + this.tempFile);
DeleteFileUtil.delete(new StringBuilder(this.tempFile).toString());
        }

    }

这样运行大部分程序都可以,也可以防止某些死循环(后面发现这实在是一个坑)。

但是代码中要是有输入的语句例如input,那么在获得输出的代码那里就会阻塞,也就是这里:while ((s = in.readLine()) != null)

要解决这个问题,必须多线程,把输入的部分另开一条线程。如果嫌麻烦,直接在监测代码,如果包含input,就不执行了,简单粗暴。如果非要首先输入的功能,那实在是挺麻烦的。我是这么做的。

首先把输入流搞一个类:

public class ProcessInput implements Runnable {
    private Process process;
    private String input;

    public ProcessInput(Process process) {
        this.process = process;
    }

    public void setInput(String input) {
        this.input = input;
    }

    @Override
    public void run() {
        System.out.println("ProcessInput run");
        try {
            while (true) {
                if (input != null) {
                    System.out.println("接收到:"+input);
                    process.getOutputStream().write(input.getBytes());
                    process.getOutputStream().write(System.lineSeparator().getBytes());
                    process.getOutputStream().flush();
                    input = null;
                }
                Thread.sleep(500);
                System.out.println(" waiting...");
                if(!process.isAlive()){
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后这样启动:

private ProcessInput input; 
private ProcessInput initInputProcess() throws InterruptedException {
    processInput = new ProcessInput(process);
    processInputThread = new Thread(processInput);
    processInputThread.setName(process+"_python_processInputThread");
    processInputThread.start();
    processInputThread.join();
    if (processInput != null) {
        System.out.println("t1 run " + processInput);
    } else
        System.out.println("t1 run");
    return processInput;
}

而接收用户输入的那端:

@PostMapping("/processInput")
    public CommonMessage processInput() throws IOException, InterruptedException {
        CommonMessage message = new CommonMessage();
        String inputString = request.getParameter("input");
      
        if (input == null) {
            message.setInfo("当前没有要输入的进程");
            message.setData("");
        } else if (pythonRunner.getProcess().isAlive()) {
            input.setInput(inputString);
            Thread.sleep(2000);
            message.setData(pythonRunner.result);
        } else {
            message.setInfo("当前没有要输入的进程");
        }

        if (!process.isAlive())
            pythonRunner.getPythonCompile().getProcessInputThread().interrupt();
        return message;
    }
用户输入的东西再给到input
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值