您的位置:首页 > 大数据

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()函数这里,问题就在于脚本的输出结果是在进程执行完之后才读取,一个好的解决办法就是新开一个清理线程来不断清空缓冲区,也就是输出和读取同时进行,代码如下:

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标识符结束了(可以用小数据试验一下)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息