如果你看到这篇文章,相信你肯定使用java新建过子进程,去执行shell命令,并且肯定耗费了不少时间。你可能会认为java自身的Runtime.exec()
很简单,而Apache Commons Exec太过臃肿,纯粹是在浪费时间。
但是,我在使用Runtime.exec()
的过程时,经历了一系列痛苦的过程。一起来看下commons exec是怎么把这一过程变简单的。
第一个例子
下面是一个简单的例子,我们调用了命令行 AcorRd32.exe,当然前提是你的系统中有这个东西。
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);
上面的代码执行后,我们打印出了pdf文档中的内容,但是运行抛出异常了。原因是Acrobat Reader运行结束后,它的返回值是1,而一般情况下认为返回值为1是错误的,所以我们需要修改一下代码。
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
int exitValue = executor.execute(cmdLine);
是否使用Watchdog
我们的程序输出了pdf内容。但是如果在输出过程中,我们的程序因为各种原因hang住了,怎么办?启动任务很简单,但是如果子进程失败了怎么办。Commons-exec提供了watchdog来解决这一问题。下面的代码中,如果子进程运行超过6秒,那么就强制结束它。
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);
引号很有用
上面的代码还有个问题,如果输入的文件路径中含有空格,会有异常。
> AcroRd32.exe /p /h C:\Document And Settings\documents\432432.pdf
解决方法是,使用引号将文件路径括起来:
String line = "AcroRd32.exe /p /h \"" + file.getAbsolutePath() + "\"";
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);
逐步生成CommandLine对象
上面的引号问题,是因为commons-exec错误地分割了我们的路径字符串,导致文件路径错误,我们可是使用CommandLine对象提供的方法,来避免手动拼装命令。
Map map = new HashMap();
map.put("file", new File("invoice.pdf"));
CommandLine cmdLine = new CommandLine("AcroRd32.exe");
cmdLine.addArgument("/p");
cmdLine.addArgument("/h");
cmdLine.addArgument("${file}");
cmdLine.setSubstitutionMap(map);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);
异步执行
现在为止,我们的程序可以良好运行了,但是还不适用生产,原因是它是阻塞的,在子进程结束前,它会一直阻塞我们的主进程。现在我们要把它变成非阻塞的。下面的代码,我们创建了一个ExecuteResultHandler对象,将它传给Executor,让它可以异步执行任务。ResultHandler会接受子进程抛出的一切异常。
CommandLine cmdLine = new CommandLine("AcroRd32.exe");
cmdLine.addArgument("/p");
cmdLine.addArgument("/h");
cmdLine.addArgument("${file}");
HashMap map = new HashMap();
map.put("file", new File("invoice.pdf"));
commandLine.setSubstitutionMap(map);
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
ExecuteWatchdog watchdog = new ExecuteWatchdog(60*1000);
Executor executor = new DefaultExecutor();
executor.setExitValue(1);
executor.setWatchdog(watchdog);
executor.execute(cmdLine, resultHandler);
//一段时间后,resultHandler的回调方法会被唤醒,我们可以查看其返回值
int exitValue = resultHandler.waitFor();
本教程中中的打印任务,一份完整的代码参考此处,http://commons.apache.org/proper/commons-exec/xref-test/org/apache/commons/exec/TutorialTest.html
获取程序输出的例子
package com.yeetrack.weixinalert;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Created by Xuemeng Wang on 15/4/2.
*/
public class ShellUtil {
DefaultExecutor defaultExecutor;
ByteArrayOutputStream outputStream;
ByteArrayOutputStream errorStream;
PumpStreamHandler pumpStreamHandler;
public ShellUtil()
{
defaultExecutor = new DefaultExecutor();
outputStream = new ByteArrayOutputStream();
errorStream = new ByteArrayOutputStream();
pumpStreamHandler = new PumpStreamHandler(outputStream, errorStream);
defaultExecutor.setStreamHandler(pumpStreamHandler);
}
public void execute(CommandLine commandLine)
{
try {
defaultExecutor.execute(commandLine);
} catch (IOException e) {
e.printStackTrace();
}
}
public String getOutAsString()
{
return outputStream.toString();
}
public String getErrorAsString()
{
return errorStream.toString();
}
}
版权声明
本站文章、图片、视频等(除转载外),均采用知识共享署名 4.0 国际许可协议(CC BY-NC-SA 4.0),转载请注明出处、非商业性使用、并且以相同协议共享。
© 空空博客,本文链接:https://www.yeetrack.com/?p=1120
近期评论