Java代码中调用shell脚本和python脚本并获得输出结果(分为小数据量和大数据量)
2015-12-23 13:31
846 查看
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()函数这里,问题就在于脚本的输出结果是在进程执行完之后才读取,一个好的解决办法就是新开一个清理线程来不断清空缓冲区,也就是输出和读取同时进行,代码如下:
其中,在脚本执行执行完后调用sleep()让主线程睡眠一秒,否则会导致清理线程可能会还没拿到缓冲区数据就被end标识符结束了(可以用小数据试验一下)。
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标识符结束了(可以用小数据试验一下)。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python动态类型的学习---引用的理解
- Python3写爬虫(四)多线程实现数据爬取
- 垃圾邮件过滤器 python简单实现
- 介绍一款信息管理系统的开源框架---jeecg
- 下载并遍历 names.txt 文件,输出长度最长的回文人名。
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- 运维入门