使用java编写一个调用第三方可执行文件的windows命令行工具
原创
©著作权归作者所有:来自51CTO博客作者人称左直拳的原创作品,请联系作者获取转载授权,否则将追究法律责任
客户有一批数据需要使用一个叫wodASC.exe的程序来处理。该程序是个命令行工具,好像是用fortran写的,比较坑,后面不能带参数,只能在运行它之后,输入待处理的文件名称,选转换字段,有点繁琐,并且每次只能处理一个文件。数据文件非常多,估计好几千个,靠人工处理,几乎不可能。
一、原理
想办法写程序来处理。思路是,首先,我们写的代码,需要调用wodASC.exe;其次,调用过程中,需要与之交互。以往有写过调用外部程序的代码,但传递给外部程序的参数都是附在后面,位于同一行命令,与外部程序交互没有弄过。试了许久,好不容易弄出来了,介绍如下。
其中最为关键的地方,是通过process.getOutputStream().write()与外部程序交互,给它喂参数。
其次是命令行。我们给Process调用的命令行类似这个样子:
cmd /k c: && cd c:\\temp\\data && e:\\wodPressor\\wodASC.exe
本命令行是一个复合命令行,里面有好几个命令,中间用 “&&” 隔开。
这个命令行意思是先到某个盘,比如c盘,然后进入指定的文件夹,调用当前程序所在位置的wodASC.exe这个程序。
二、主要代码:
private void doIt(File file, String[] option) {
try {
String command = getCommand(file);//装配好命令行
Process process = Runtime.getRuntime().exec(command);
//读取外部程序的输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "gbk"));
//往外部程序输入,感觉怎么名字刚好倒过来了,getOutputStream()
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
String fileName = file.getName();
//将文件名传给外部程序
//“\n”是回车
writer.write(fileName + "\n");
//这句也很重要,推给外部程序
writer.flush();
//将选项1传给外部程序
writer.write(option[0] + "\n");
writer.flush();
//将选项2传给外部程序
writer.write(String.format("%s#%s", fileName, option[1]) + "\n");
writer.flush();
//将选项3传给外部程序
writer.write("0\n");
writer.flush();
//参数喂完
writer.close();
//释放process
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
//命令行也值得说一下
//本命令行是一个复合命令行,里面有好几个命令,中间用 "&&" 隔开。
//这个命令行意思是先到某个盘,比如c盘,然后进入指定的文件夹,调用当前程序所在位置的wodASC.exe这个程序。
private static final String CMD = "cmd /k %s: && cd %s && %s\\wodASC.exe";
private String getCommand(File f) {
String folder = f.getParent();//待处理的文件夹
String disk = getDisk(folder);//盘符
return String.format(CMD, disk, folder, this._curPath);
}
三、补充事项
上面给出的代码,是一次性、一口气,将多个参数喂给外部程序。但是,我在测试过程中,为方便测试,简单起见,是写了一个批处理文件来代替wodASC.exe这个外部程序。但喂参数的代码却有所不同:
1、批处理
set /p a=please input a:
echo a-%a%
set /p b=please input b:
echo b-%b%
pause>nul
2、测试代码
public static void test() {
ProcessBuilder builder = new ProcessBuilder("c:/temp/test.bat");
builder.redirectErrorStream(true);
Process process = null;
try {
process = builder.start();
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
while (true) {
String line = reader.readLine().trim();
if (line.endsWith("input a:")) {
writer.write("AAA\n");
writer.flush();
} else if (line.endsWith("input b:")) {
writer.write("BBB\n");
writer.flush();
} else {
System.out.println(line);
}
if (line.endsWith("pause1>nul")) {
writer.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
这里面用了while,一直在等待程序喂参数,而不是像上面那样,呼啦啦,一口气喂完。而且喂的时候,是根据程序的输出来决定喂什么参数。但这种方式,对我要真正调用的wodASC.exe却不起作用。在这个地方,着实被坑了一把。
这其中是啥原因,还不得而知。