0

I have a Java code calling Python through an asynchronous process, and I want the Python process to listen to stdout from Java until something printed.

Following is the java code:

import java.io.*;

public class host {
    public static void main(String[] args) throws Exception{
        System.out.println("java starts at " + System.currentTimeMillis() + " ms");
        ProcessBuilder pb = new ProcessBuilder("python","a.py");
        Process tr = pb.start();
        System.out.println("First msg");
        System.out.println("Second msg");
        Thread.sleep(3000);
        System.out.println("x");
        System.out.println("java ends at " + System.currentTimeMillis() + " ms");
    }
}

and following is the python code:

import sys
import time
if __name__=="__main__":
    fo=open("a.txt","w")
    fo.write('python starts at: %.0f\n'%(time.time()*1000))
    line = sys.stdout.readline()
    while(line != "x\n"):
        fo.write(line+"\n")
        line = sys.stdout.readline()
    fo.write('python ends at: %.0f\n'%(time.time()*1000))
    fo.close()

However, the Python process seemed not be able to capture the stdout from Java. Since I am new to Java, I am not sure whether there is something fundamentally wrong or not, and whether the above model provides an effective way between Java and Python communication.

EDIT (UPDATE)

Based on the answers/comments, I modified my Java code as follows:

import java.io.*;

public class host {
    public static void main(String[] args) throws Exception{
        System.out.println("java starts at " + System.currentTimeMillis() + " ms");
        ProcessBuilder pb = new ProcessBuilder("python","a.py");
        Process tr = pb.start();
        PrintStream ps = new PrintStream(tr.getOutputStream());
        ps.println("First msg"); ps.flush();
        ps.println("Second msg"); ps.flush();
        Thread.sleep(3000);
        ps.println("x"); ps.flush();
        System.out.println("java ends at " + System.currentTimeMillis() + " ms");
    }
}

and changed python script as follows:

import sys
import time
if __name__=="__main__":
    fo=open("a.txt","w")
    fo.write('python starts at: %.0f\n'%(time.time()*1000))
    line = sys.stdin.readline()
    while(line != "x\n"):
        fo.write(line+"\n")
        line = sys.stdin.readline()
    fo.write('python ends at: %.0f\n'%(time.time()*1000))
    fo.close()

And following is the output:

python starts at: 1453263858103
First msg

First msg

Second msg

python ends at: 1453263863103
Hailiang Zhang
  • 17,604
  • 23
  • 71
  • 117
  • Have you tinkered with redirect? https://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.Redirect.html – Heman Gandhi Jan 19 '16 at 22:25
  • Your ProcessBuilder and the new runtime environment it creates when starting python has its own in, out and err streams. They are different from the Syste.in/out/err. Use the ProcessBuilder.redirectInput(). – JayC667 Jan 19 '16 at 22:26
  • @ JayC667 That's what I thought also, but how do I pass Java stdout to python? – Hailiang Zhang Jan 19 '16 at 22:27
  • See http://stackoverflow.com/questions/14165517/processbuilder-forwarding-stdout-and-stderr-of-started-processes-without-blocki as a simple example – JayC667 Jan 19 '16 at 22:29
  • you can't *read* from stdout. you read from stdin. – njzk2 Jan 19 '16 at 22:44
  • inheritIO does not do what you want. it just means that python can read form the same stdin as java. They will be parallel (but you want serial). – njzk2 Jan 19 '16 at 22:45
  • what you need to do is write to the output stream of the process you created. – njzk2 Jan 19 '16 at 22:46

2 Answers2

2

The receiving process should listen to stdin, not stdout.

Then pipe the output from java to python:

java -jar myjava.jar | python mylistener

rotten
  • 1,580
  • 19
  • 25
1

In java, write to the process you created:

ProcessBuilder pb = new ProcessBuilder("python","a.py");
Process tr = pb.start();
tr.getOutputStream().println("First msg");

In python, read from stdin:

line = sys.stdin.readline()
njzk2
  • 38,969
  • 7
  • 69
  • 107