最近在项目中用FlexPaper+SWFTools实现仿百度文库的功能,其中需要将pdf转化为swf格式,这需要java来执行外部命令。以下是我截取pdf文件转swf文件的关键代码
r = Runtime.getRuntime();
Process p=null;
try {
p = r.exec("d:/swftools/pdf2swf.exe "
+"\""+ pdfFile.getPath()+"\"" + " -o "
+"\""+swfFile.getPath()+"\""+ " -T 9");
上述代码中‘pdfFile.getPath()’是要转化的pdf源文件,前后加上双引号,可以解决文件名字存在空格的情况。例如执行命令:d:/swftools/pdf2swf.exe“d:/upload/file/改进金融监管 推动业务创新.pdf” –o “d:/upload/file/改进金融监管 推动业务创新.pdf”。-o 参数的作用是指明转化后swf文件的存放位置。
上述代码,对于源文件名中存在一个空格的有效,对于含有2个空格以上的文件名的文件的转化无效。通过Process类的getErrorStream(),打印错误输出流的信息,得知,程序报无法打开’xx xx.pdf’的错误,细心发现,文件名中的空格变成了一个空格,我源文件的名字原本是有2个空格的,为什么用Runtime.getRuntime().exec()会自动截取我的文件名,把空格变成一个?
现在可以将问题定位在Runtime类exec方法中了。通过查看API文档,无果。
通过导入源码包,查看源码,哈哈,发现代码最终调用的Runtime,exec的另一个重载方法。
问题就出现在StringTokenizer类这里了
public Process exec(String command, String[] envp, File dir)
throws IOException {
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
}
这里使用默认空格来分割字符串,这也是问题的根源所在了。因为使用空格分割,所以无论文件名中有多少个连续空格,最后都会变成一个空格,文件名变了,当然无法转化了。
现在知道不能使用Runtime这个类的exec方法来执行外部转化命令了。执行查看源代码,看到这里,忽然有种,山上水复疑无路,柳暗花明又一村的感觉。再一次,感慨,开源真好!
原来Runtime的exec方法最终也是用到ProcessBuilder类,看到这里,我果断打开Java API,查看ProcessBuilder类。
我想到,既然Runtime的exec方法最终也是将字符串(要执行的命令)分割成字符串数组,那么我自己来分割字符串,就不会受空格制约了。将命令分别add到一个list中,再调用
ProcessBuilder(List command)这个构造函数, Process p=newProcessBuilder(command).start();
// r = Runtime.getRuntime();
Process p=null;
try {
// p = r.exec("d:/swftools/pdf2swf.exe "
// +"\""+ pdfFile.getPath()+"\"" + " -o "
// +"\""+swfFile.getPath()+"\""+ " -T 9");
List command=new ArrayList();
command.add("d:/swftools/pdf2swf.exe");
command.add("\""+ pdfFile.getPath()+"\"");
command.add("\""+swfFile.getPath()+"\"");
command.add("-T");
command.add("9");
p=new ProcessBuilder(command).start();
以下是控制台输出信息,
哈哈,至此,因为文件名中含有空格,造成转化失败问题得到圆满解决。