2

Suppose I have started a subprocess in Java, that may write to stdout and stderr:

Process subprocess = Runtime.getRuntime().exec(…);

I want to read all its stdout and stderr; or just ignore them.

  1. If I do like this:

    readAllFrom(subprocess.getInputStream()); //stdout is getInputStream, weird!
    readAllFrom(subprocess.getErrorStream()); //stderr
    

    … it'll stuck, if subprocess first tries to output data to stderr and thus blocks at that point.

    And if I do something like this:

    while (…) {
        readLineFrom(subprocess.getInputStream());
        readLineFrom(subprocess.getErrorStream());
    }
    

    … the risk, actually, seems to be the same.

  2. If I do like this:

    while (…) {
        nonblockingReadFrom(subprocess.getInputStream());
        nonblockingReadFrom(subprocess.getOutputStream());
    }
    

    where nonblockingReadFrom can be something like:

    … nonblockingReadFrom(InputStream stream) {
        byte[] buffer = new byte[…];
        stream.read(buffer, 0, Math.min(stream.available(), buffer.length));
        …
    }
    

    … it will make useless 100%-CPU-loads, if subprocess outputs data with some pauses.

  3. Of course, I can create separate thread. Something like here (1, 2). But my question is about doing all in the same thread. Probably, something like Java interface to select system call is needed for that.

So, the question is: Is it possible to handle correctly stdout and stderr of a java.lang.Process-typed subprocess in Java without using additional threads or temporary files?

Community
  • 1
  • 1
Sasha
  • 3,599
  • 1
  • 31
  • 52
  • Have you seen this - http://stackoverflow.com/questions/14165517/processbuilder-forwarding-stdout-and-stderr-of-started-processes-without-blocki ? – GhostCat Oct 08 '16 at 11:19
  • @GhostCat, seems to be unrelated. Accepted answer uses stream gobblers, which is multi-threaded solution. Evgeniy Dorofeev's answer just redirects stdout and stderr of subprocess to stdout and stderr of main process accordingly, which isn't my goal. – Sasha Oct 08 '16 at 11:46
  • Is redirecting stderr into stdout an option? If so, [this question](http://stackoverflow.com/questions/3754841) may help. – Luke Woodward Oct 08 '16 at 12:31
  • Please check this link http://stackoverflow.com/questions/5711084/java-runtime-getruntime-getting-output-from-executing-a-command-line-program. It may be helpful for your purposes. – eg04lt3r Oct 08 '16 at 12:32
  • @LukeWoodward, of course no. – Sasha Oct 08 '16 at 13:12
  • @eg04lt3r, the accepted answer from your link, per my opinion, demonstrates wrong approach (it's actually aproach #1 from my question). The program, AFAIK, will block if a subprocess first tries to output to stderr, and only then to stdout. If I'm wrong, please, tell me why. – Sasha Oct 08 '16 at 13:17
  • 1) See also [When Runtime.exec() won't](http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html) for many good tips on creating and handling a process correctly. Then ignore it refers to `exec` and use a `ProcessBuilder` to create the process. Also break a `String arg` into `String[] args` to account for things like paths containing space characters. 2) For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). – Andrew Thompson Oct 08 '16 at 13:42
  • @AndrewThompson, thank for a good link, I actually read it before posting my question (it doesn't address my question, it proposes stream gobblers, which are actually multi-threaded solution). As for MCVE and SSCCE, I can't provide any example, as I don't know how to solve my theoretical question. – Sasha Oct 08 '16 at 13:49
  • @AndrewThompson, actually, [MCVE](http://stackoverflow.com/help/mcve) and [SSCCE](http://www.sscce.org/) don't apply here, because I'm no discussing *problem caused by my code* or *problem with some code* at all. – Sasha Oct 08 '16 at 15:03

1 Answers1

3

No, you can't just create a SelectableChannel from the InputStream returned by a Process, this is a Java api limitation AFAICT.

Cristian Greco
  • 2,566
  • 1
  • 19
  • 24
  • 1
    *"I think you can just wait for process termination and then inspect both streams."* <— Won't subprocess block, if it tries to output a lot of data, and I'm not reading the streams? – Sasha Oct 08 '16 at 13:52
  • Yes, it will block if you don't consume the streams (you can try it yourself by running a `cat /dev/urandom` subprocess). That's why you should use a thread if the subprocess is going to produce a considerable amount of output and you don't want to block the parent while reading. – Cristian Greco Oct 08 '16 at 13:53
  • 1
    then, please, remove second part of your answer (which IMO confuses readers), so that I can't accept it (if I understood it correctly, the first part means ***No, as of Java 8 it's currently impossible.***). – Sasha Oct 08 '16 at 13:57
  • While this answer indicates that turning stdin and stdout into Selectable channels is impossible, I still wonder if there is any *other* way in Java to achieve the same goal: reacting to messages in stdin and stdout simultaneously. – Luke 10X Apr 07 '23 at 17:45