0

From within my Java code, I have a call to an external program, I use the following:

int returnCodeC = 0;
String cmnd = "dia -fa -fn res" + file1;
final Process processCC = Runtime.getRuntime().exec(cmnd);
BufferedReader bufC = new BufferedReader(new InputStreamReader(processCC.getInputStream()));
returnCodeC = processCC.waitFor();
    } catch (Exception e1) {e1.printStackTrace();}}

The output from the call to the external program dia should be written in a file named file1 This was functioning normally until today. I guess the problem is that when the output from dia is huge, i am getting no output. is there a size limit for BufferReader ?

SLA
  • 363
  • 2
  • 4
  • 11
  • Are you sure you are still reading anything from dia? I mean, it may not be a buffer limitation. – Rafael Saraiva Nov 04 '14 at 16:50
  • When I run the dia command from the terminal .. everything works well.. even when I call it from java it used to work ( just in case the input files used by dia were small.. and thus the output size was small) now when running dia from java with big input files.. the output (which is large) is not written in the output file. – SLA Nov 04 '14 at 16:55
  • I am not sure if its a buffer limitation ptoblem.. I still do not know what is the problem. – SLA Nov 04 '14 at 16:57
  • I see, what you should do is use the bufC call read(char[] cbuf, int off, int len) to read chunks of the dia output each time. It is not good practice to use load large buffers to memory. Even if it worked it would still be a bad practice. If you need a more detailed explanation feel free to say so. – Rafael Saraiva Nov 04 '14 at 17:00

2 Answers2

0

This is more of a comment but a popper answer, but my bad reputation does not allow me to post a comment.

Your process will block if either stdout or stderr overflow their respective buffer size.

Try your command in a shell to see what happens, and start threads to read stdterr and stdout.

Edit: here is what I found on the net, and it works for me when I don't need the content of stdout and stderr, but only the command to run. I call the dropOutput just before the processCC.waitFor().

private int dropOutput(final Process p) {

    final Thread t = new Thread("drop") {

      @Override
      public void run() {
        _dropOutput(p);
      };
    };

    t.start();
    int ev = 0;
    Timer timer = null;
    try {
      timer = new Timer(true);
      final InterruptTimerTask interrupter = new InterruptTimerTask(Thread.currentThread());
      timer.schedule(interrupter, 2 /*seconds*/* 1000 /*milliseconds per second*/);
      if (p.waitFor() != 0) {
        ev = p.exitValue();

      }
    } catch (final InterruptedException e) {
      //  e.printStackTrace();
    } finally {
      timer.cancel(); // If the process returns within the timeout period, we have to stop the interrupter
                      // so that it does not unexpectedly interrupt some other code later.

      Thread.interrupted(); // We need to clear the interrupt flag on the current thread just in case
                            // interrupter executed after waitFor had already returned but before timer.cancel
                            // took effect.
                            //
                            // Oh, and there's also Sun bug 6420270 to worry about here.
    }
    return ev;
  }

  /**
   * Just a simple TimerTask that interrupts the specified thread when run.
   */
  class InterruptTimerTask extends TimerTask {

    private final Thread thread;

    public InterruptTimerTask(final Thread t) {
      this.thread = t;
    }

    @Override
    public void run() {
      thread.interrupt();
    }

  }

  private void _dropOutput(final Process p) {
    final InputStream istrm = p.getInputStream();
    // final InputStream istrm = p.getErrorStream();
    final InputStreamReader istrmrdr = new InputStreamReader(istrm);
    final BufferedReader buffrdr = new BufferedReader(istrmrdr);

    @SuppressWarnings("unused")
    String data;
    try {
      while ((data = buffrdr.readLine()) != null) {
        // System.out.println(data);
      }
    } catch (final IOException e) {
      // do nothing
    }
  }
Gyro Gearloose
  • 1,056
  • 1
  • 9
  • 26
0

Now that i think i understand the problem better i would advise you to use processBuilder. It allows you to have exceptional control over the proccess output. Here is a link that might help you: ProcessBuilder

The proccess receives an string array as argument so use String [] cmd = {"dia", "-fa", "-fn", "res"};

Rafael Saraiva
  • 908
  • 2
  • 11
  • 23
  • Runtime.getRuntime().exec(cmnd); is quite happy with a single String. Maybe that use is outdated, but I doubt this is is the cause of the problem here. – Gyro Gearloose Nov 04 '14 at 18:33
  • @SLA , I'm a bit confused: did this (and only this) really solve your problem? Could you please post the running code? Thanks. – Gyro Gearloose Nov 05 '14 at 23:04