1

I'm using a C# Process to run the following Java code with the java command:

public class Test {
    public static void main(String[] args) throws Exception {
        Thread.sleep(2000);
        System.out.print("Hello worl\nd 1!");
        Thread.sleep(2000);
        System.out.println("Hello world 2!");
    }
}

I'm using the following code to listen to the output:

run.OutputDataReceived += (_, args) => { /* handle output */ };
run.Start();
run.BeginOutputReadLine();

Ideally, OutputDataReceived should be fired twice, with the coressponding values for args.Data:

  1. "Hello worl\nd 1!"
  2. "Hello world 2!\n"

Instead, the newlines are used to determine when OutputDataReceived is fired. This ends up giving 3 calls to the event, with the corresponding values to args.Data:

  1. "Hello worl"
  2. "d 1!Hello world 2!"
  3. null

How would I run code to handle output according to my first scenario (each time stdout is updated) instead of what is currently happening/the second scenario (whenever stdout receives a new line)? In addition, how would I do the same for stderr as well?

  • 1
    Does this answer your question? [Read Process StandardOutput before New Line Received](https://stackoverflow.com/questions/22991115/read-process-standardoutput-before-new-line-received) – Progman Jul 31 '22 at 07:48

2 Answers2

1

For anyone else with this problem, you can use this solution described in this answer to get live output.

0

I think what you want is impossible, and this is by design.

These text streams ain’t made of discrete messages, it’s a continuous stream of bytes very similar to a TCP socket.

If you control both producing and consuming sides of the stream, you can workaround by implementing some framing protocol on top of that stream. An easy way which might be good enough for you —separate messages with double newlines. This way, on the C# side you can write code which reads lines accumulating in a buffer, search for double newlines, when found or end of stream raise an event to handle a complete message, and unless end of stream move the remaining portion of the buffer to the start of the buffer.

Another workaround is using some other IPC mechanism instead of standard output. On Windows, named pipes support PIPE_TYPE_MESSAGE flag which causes the pipe to preserve message boundaries. Similarly, Linux kernel supports SOCK_DGRAM for Unix domain sockets. In both cases, a common design pattern looks like that: 1. Generate unique pipe/socket name in the parent C# process, for instance by generating a new GUID and printing that GUID. 2. Create the pipe or socket of that name. 3. Pass that name to the child Java process through a command-line argument, or an environment variable. 4. In the Java process, connect the pipe/socket by the name, you then have a message oriented two way communication channel between your two processes.

Soonts
  • 20,079
  • 9
  • 57
  • 130
  • I wasn't able to find any built-in solution. I did a *lot* more digging and stumbled across [this answer](https://stackoverflow.com/questions/4501511/c-sharp-realtime-console-output-redirection) that worked like a charm. – Yogesh Thambidurai Jul 31 '22 at 17:15