Nick
Nick

Reputation: 892

Process won't run unless printing output + Processbuilder

I've come across a strange issue. I've used process builder several times to call an executable from a program but have never encountered this before. For debug purposes I made a method which prints the output of the executable to System.out. Everything worked fine and my program nicely exported all of the test gifs I ran.

When it came time to run this program properly for 1000+ gifs I commented out the printout method to improve performance. Once the whole program had run I come back to find that the exportGif did not work. The program ran with no errors but the calling of the process simply did not export the gifs as expected.

After isolating lines in the printout method it seems that the deciding bit of code is the reader.readLine(). Why would this be the case? The executable should have already run, the debug method should only read the output stream after the fact, correct? I'd rather not loop through it's output stream every time as it causes the program to slow considerably.

    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);
    }

EDIT

One thing I should add. I noticed that when I comment out the debug method it clocks through all 1000+ iterations in less than ten minutes, But, of course the gifs do not export (the executable doesn't run...? Not sure).

When I include the printout method it is a lot slower. I tried running it overnight but it got stuck after 183 iterations. I've tried profiling to see if it was causing some thrashing but the GC seems to run fine.

Upvotes: 2

Views: 423

Answers (1)

assylias
assylias

Reputation: 328598

You need to consume the output of the Process or it may hang. So you can't comment out printProcessOutput(process);. Instead, comment out the lines that actually do the printing:

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());

I generally use this method, which also redirects the error stream:

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);
  }
}

Upvotes: 2

Related Questions