swftools转换文件时线程堵塞问题的解决方法 【转】
在使用swftools工具作转换时,最需要注意的是对转换过程中的输入流的处理和出错流的处理。不然,若对流入流(转换过程中会产生的输入流信息有类似如下:NOTICE ?processing PDF page 10 (595x842:0:0) (move:0:0)等等的打印时提示信息)处理,那么,转换不能进行下去,线程会堵塞,而不对出错流进行处理,那么当遇到有加密和损坏的文件转换时,也会导致线程的堵塞。对于输入流和出错流的处理,简单处理如下:
?
?
- //注意destPath最后必须带文件分隔符//这个用来转换的swfTool工具,一但待转换的文件有不可识别的字符在里面时,它就会堵塞在那里。这个情况要处理掉public String PDF2SWF(String sourcePath, String destPath,String fileName) throws Exception {// 目标路径不存在则建立目标路径File dest = new File(destPath);if (!dest.exists()) {dest.mkdirs();}// 源文件不存在则返回File source = new File(sourcePath);if (!source.exists()) {log.info("pdf转换swf失败,源文件不存在!");throw new Exception();}//因为下面进行系统调用,这样就会把系统执行的操作新开启一个线程(在此linux也叫进程),所以它和主扫描程序是独立运行,所以下次还会扫描这个转换中的文件,所以这里要将它设置为不可读,source.setReadable(false);FileConvertUtil fileConvertUtil = new FileConvertUtil();fileName = fileConvertUtil.getFileName(fileName);//获取文件名String outputFile = destPath + fileName + ".swf";log.debug("开始调用swftools转换pdf文件:" + outputFile);List<String> command = newArrayList<String>();command.add(ProjectInit.swftoolsPath);//从配置文件里读取command.add("-z");//command.add("-B");//command.add("rfxview.swf");command.add("-s");command.add("flashversion=9");command.add("-s");command.add("poly2bitmap");//加入poly2bitmap的目的是为了防止出现大文件或图形过多的文件转换时的出错,没有生成swf文件的异常//windows平台下//command.add("languagedir=C:/xpdf/chinese-simplified/");command.add(sourcePath);command.add("-o");command.add(outputFile);ProcessBuilder processBuilder = new ProcessBuilder();processBuilder.command(command);Process process = processBuilder.start();dealWith(process);//处理输入流和出错流try {process.waitFor();//等待子进程的结束,子进程就是系统调用文件转换这个新进程} catch (InterruptedException e) {e.printStackTrace();}log.debug("转换完成!");return outputFile;}private void dealWith(final Process pro){// 下面是处理堵塞的情况try {new Thread(){public void run(){BufferedReader br1 = new BufferedReader(new InputStreamReader(pro.getInputStream()));String text;try {while ( (text = br1.readLine()) != null) {System.out.println(text);}} catch (IOException e) {e.printStackTrace();}}}.start();} catch (Exception e) {e.printStackTrace();}try {new Thread(){public void run(){BufferedReader br2 = new BufferedReader(new InputStreamReader(pro.getErrorStream()));//这定不要忘记处理出理时产生的信息,不然会堵塞不前的String text;try {while( (text = br2.readLine()) != null){System.err.println(text);}} catch (IOException e) {e.printStackTrace();}}}.start();} catch (Exception e) {e.printStackTrace();}}
?但是这里还是有问题的,因为这里调用process.start方法就开启一个线程进文件进行转换,而若还没开启转换,而线程切换,将文件转换的线程交这里对输入流的线程,那么由br1.readLine()读入的数据就是为null,所以这里的对输入流的处理也就起不了作用就会跳出while循环,而这时又将cpu的使用权交给swftools转换时,那么由于它的流入流和出错流没有线程来处理,所以它又会堵塞。因此使用下面的方式来做可以避免这个问题:
?
?
- //注意destPath最后必须带文件分隔符//这个用来转换的swfTool工具,一但待转换的文件有不可识别的字符在里面时,它就会堵塞在那里。这个情况要处理掉public String PDF2SWF(String sourcePath, String destPath,String fileName) throws Exception {// 目标路径不存在则建立目标路径File dest = new File(destPath);if (!dest.exists()) {dest.mkdirs();}// 源文件不存在则返回File source = new File(sourcePath);if (!source.exists()) {log.info("pdf转换swf失败,源文件不存在!");throw new Exception();}//因为下面进行系统调用,这样就会把系统执行的操作新开启一个线程(在此linux也叫进程),所以它和主扫描程序是独立运行,所以下次还会扫描这个转换中的文件,所以这里要将它设置为不可读,source.setReadable(false);FileConvertUtil fileConvertUtil = new FileConvertUtil();fileName = fileConvertUtil.getFileName(fileName);//获取文件名String outputFile = destPath + fileName + ".swf";log.debug("开始调用swftools转换pdf文件:" + outputFile);List<String> command = newArrayList<String>();command.add(ProjectInit.swftoolsPath);//从配置文件里读取command.add("-z");//command.add("-B");//command.add("rfxview.swf");command.add("-s");command.add("flashversion=9");command.add("-s");command.add("poly2bitmap");//加入poly2bitmap的目的是为了防止出现大文件或图形过多的文件转换时的出错,没有生成swf文件的异常//windows平台下//command.add("languagedir=C:/xpdf/chinese-simplified/");command.add(sourcePath);command.add("-o");command.add(outputFile);ProcessBuilder processBuilder = new ProcessBuilder();processBuilder.command(command);Process process = processBuilder.start();//dealWith(process);//改用下面的方式来处理:InputStreamWathThread inputWathThread = new InputStreamWathThread(process);inputWathThread.start();ErrorInputStreamWathThread errorInputWathThread = new ErrorInputStreamWathThread(process);errorInputWathThread.start();try {process.waitFor();//等待子进程的结束,子进程就是系统调用文件转换这个新进程inputWathThread.setOver(true);//转换完,停止流的处理errorInputWathThread.setOver(true);} catch (InterruptedException e) {e.printStackTrace();}log.debug("转换完成");return outputFile;}
?这里将流入流和出错流作为一个监视线程,两个条件作为跳出循环的判断:
1 输入流处理类:
?
?
- import java.io.BufferedReader;import java.io.InputStreamReader;import org.apache.log4j.Logger;//这个类主要用来处理一个系统调用而新创建一个线程或进程执行期间所产生的输入流的处理public class InputStreamWathThread extends Thread {private Process process = null;private boolean over = false;private Logger logger = Logger.getLogger(getClass());public InputStreamWathThread(Process p) {process = p;over = false;}public void run() {try {if (process == null) {logger.info("process为null,无法处理文件转换");return;}//对输入流,可能是一个回车之类的输入BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));while (true) {if (process == null || over) {logger.info("处理完成");break;}String temp;while ((temp = br.readLine()) != null) {//logger.info("输入流信息:" + temp);//如这些信息:NOTICE processing PDF page 10 (595x842:0:0) (move:0:0)等等的打印时提示信息;}}} catch (Exception e) {e.printStackTrace();logger.info("发生异常" + e.getMessage());}}public void setOver(boolean over) {this.over = over;}}
?2 出错流处理类:
?
?
- import java.io.BufferedReader;import java.io.InputStreamReader;import org.apache.log4j.Logger;//这个类主要用来处理一个系统调用而新创建一个线程或进程执行期间所产生的出错流的处理public class ErrorInputStreamWathThread extends Thread {private Process process = null;private boolean over = false;private Logger logger = Logger.getLogger(getClass());public ErrorInputStreamWathThread(Process p) {process = p;over = false;}public void run() {try {if (process == null) {logger.info("process为null,无法处理文件转换");return;}//对出错流的处理BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));while (true) {if (process == null || over) {logger.info("处理完成");break;}String temp;while ((temp = br.readLine()) != null) {//logger.info("出错流信息:" + temp);;}}} catch (Exception e) {e.printStackTrace();logger.info("发生异常" + e.getMessage());}}public void setOver(boolean over) {this.over = over;}}
?
这样就可以使用process的执行完毕后通知输入流类和出错流处理类,这样就可以很好的处理调用swftools转换文件而引起的线程堵塞问题。