2017-05-05 43 views
2

我遇到了一个奇怪的问题。我多次使用过程构建器来调用程序中的可执行文件,但以前从未遇到过。为了进行调试,我制作了一个方法,将可执行文件的输出打印到System.out中。一切正常,我的程序很好地导出了我跑过的所有测试gif。进程将不会运行,除非打印输出+ Processbuilder

当需要为1000多个gif正确运行此程序时,我将打印输出方法注释掉以提高性能。一旦整个程序运行,我回来发现exportGif没有工作。该程序运行没有错误,但该过程的调用根本没有按预期输出gif。

在打印输出方法中隔离行后,似乎代码的决定位是reader.readLine()。为什么会这样呢?可执行文件应该已经运行了,调试方法应该只在事实之后读取输出流,正确吗?我宁愿不循环每次输出流,因为它会导致程序显着减慢。

private void printProcessOutput(Process process){ 
     BufferedReader reader = 
       new BufferedReader(new InputStreamReader(process.getInputStream())); 
     StringBuilder builder = new StringBuilder(); 
     String line = null; 

     try{ 
      while ((line = reader.readLine()) != null) { 
       builder.append(line); 
       builder.append(System.getProperty("line.separator")); 
      } 
     }catch(IOException e){ 
      e.printStackTrace(); 
     } 

     System.out.println(builder.toString()); 
    } 

    private void exportGIF(String dirPath) throws IOException { 
     List<String> lines = Arrays.asList("/Users/IdeaProjects/MasterFormat/MasterFormat-Java/MasterFormat/timMaster_4.1.png \"{200.0,467.0}\""); 
     Path headImageFile = Paths.get(System.getProperty("user.dir") + File.separator + "headImageInfo.txt"); 
     Files.write(headImageFile, lines, Charset.forName("UTF-8")); 

     String templatePath = dirPath + File.separator + "template.mp4"; 
     String outputPath = dirPath + File.separator; 
     String headImagePath = headImageFile.toString(); 
     String gifExportExecPath = "/Users/IdeaProjects/MasterFormat/MasterFormat-Java/MasterFormat/GIFExport"; 

     Process process = new ProcessBuilder(gifExportExecPath, "-s", templatePath, "-o", outputPath, "-h", headImagePath).start(); 

     printProcessOutput(process); 

     Files.delete(headImageFile); 
    } 

编辑

有一件事我要补充。我注意到,当我注释掉调试方法时,它会在不到10分钟内完成所有1000多次迭代计时,但是,当然gif不会导出(可执行文件不会运行...?不确定)。

当我包含打印输出方法时,速度会慢很多。我试着在一夜之间运行它,但是经过183次迭代后它陷入了僵局。我试图分析,看看它是否导致一些颠簸,但GC似乎运行良好。

+1

你写“程序,但没有任何错误”,这意味着它没有“挂”的权利?所以这是不一样的,我在这里假设:http://stackoverflow.com/questions/22953760/processbuilder-process-not-running?rq=1 – dbalakirev

回答

2

您需要使用进程的输出,否则可能会挂起。所以你不能评论printProcessOutput(process);。相反,注释掉实际上做印刷线路:

try{ 
    while ((line = reader.readLine()) != null) { 
    //builder.append(line); 
    //builder.append(System.getProperty("line.separator")); 
    } 
} catch(IOException e){ 
    e.printStackTrace(); 
} 
//System.out.println(builder.toString()); 

我一般都用这个方法,这也重定向错误流:

public static void runProcess(ProcessBuilder pb) throws IOException { 
    pb.redirectErrorStream(true); 
    Process p = pb.start(); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 
    String line; 
    while ((line = reader.readLine()) != null) { 
    //System.out.println(line); 
    } 
} 
+0

从Javadoc进程:“默认情况下,创建的子进程没有它的所有标准I/O(即stdin,stdout,stderr)操作将被重定向到父进程,[...]因为一些本地平台仅为标准输入和输出流提供有限的缓冲区大小,未及时写入输入流或读取子流程的输出流可能导致子流程阻塞,甚至死锁。“所以是的,这个过程实际上正在等待完成,你可以得到内存泄漏而不会消耗err/out流。 –