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

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


   
   
   
   
  1. public String python(String pythonPath, String[] params) {
  2. File file = new File(pythonPath);
  3. if (!file.exists()){
  4. return "python脚本不存在!";
  5. }
  6. String[] command = Arrays.copyOf( new String[]{ "python", pythonPath}, params.length + 2);
  7. System.arraycopy(params, 0, command, 2, params.length);
  8. List res = new ArrayList<>();
  9. try {
  10. Process process = Runtime.getRuntime().exec(command, null, null);
  11. process.waitFor();
  12. Scanner scanner = new Scanner(process.getInputStream());
  13. while (scanner.hasNextLine()) {
  14. String line = scanner.nextLine();
  15. res.add(line);
  16. }
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. return "success";
  23. }

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

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


    
    
    
    
  1. public String python(String pythonPath, String[] params) {
  2. File file = new File(pythonPath);
  3. if (!file.exists()){
  4. return "python脚本不存在!";
  5. }
  6. String[] command = Arrays.copyOf( new String[]{ "python", pythonPath}, params.length + 2);
  7. System.arraycopy(params, 0, command, 2, params.length);
  8. List res = new ArrayList<>();
  9. try {
  10. Process process = Runtime.getRuntime().exec(command, null, null);
  11. ClearThread ct = new ClearThread(process);
  12. ct.start();
  13. process.waitFor();
  14. Thread.sleep( 1000);
  15. ct.setEnd( true);
  16. res = ct.getRes();
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. return "success";
  23. }
  24. class ClearThread extends Thread {
  25. Process process;
  26. boolean end;
  27. List res;
  28. public ClearThread(Process process) {
  29. this.process = process;
  30. end = false;
  31. res = new ArrayList<>();
  32. }
  33. @Override
  34. public void run() {
  35. if (process == null) {
  36. return;
  37. }
  38. Scanner scanner = new Scanner(process.getInputStream());
  39. while (process != null && !end) {
  40. while (scanner.hasNextLine()) {
  41. String line = scanner.nextLine();
  42. res.add(line);
  43. }
  44. }
  45. }
  46. public void setEnd(boolean end) {
  47. this.end = end;
  48. }
  49. public List getRes() {
  50. return res;
  51. }
  52. }
其中,在脚本执行执行完后调用sleep()让主线程睡眠一秒,否则会导致清理线程可能会还没拿到缓冲区数据就被end标识符结束了(可以用小数据试验一下)。


你可能感兴趣的:(Java代码中调用shell脚本和python脚本并获得输出结果(分为小数据量和大数据量))