Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java: how to both read and write to & from process thru pipe (stdin/stdout)

Tags:

java

stdin

pipe

(i'm new to java) I need to start a process and receive 2 or 3 handles: for STDIN, STDOUT, (and STDERR), so I can write input to the process and receive its output, the same way command line pipes behave (e.g. "grep")

in Python this is acheived with the following code:

from subprocess import Popen, PIPE
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
child_stdin.write('Yoram Opposum\n')
child_stdin.flush()
child_stdout.readlines()

What's the Java equivalent??

I've tried so far

Process p = Runtime.getRuntime().exec(cmd);
BufferedReader inp = new BufferedReader( new InputStreamReader(p.getInputStream()) );
BufferedWriter out = new BufferedWriter( new OutputStreamWriter(p.getOutputStream()) );
out.write( "Some Text!\n\n" );
out.flush();
line = inp.readLine();
print("response1: " + line );   // that's ok
out.write( "Second Line...\n" );
out.flush();
line = inp.readLine();
print("response2: " + line );    // returns an empty string, if it returns,,,
inp.close();
out.close();

BTW the first try works only with \n\n, but doesn't work with single \n (why?)

the following code works, but all input is given in advance, not the behavior i'm looking for:

out.write( "Aaaaa\nBbbbbb\nCcccc\n" );
out.flush();
line = inp.readLine();
print("response1: " + line );
line = inp.readLine();
print("response2: " + line );
line = inp.readLine();
print("response3: " + line );
line = inp.readLine();
print("response4: " + line );

output:

response1: AAAAA
response2: 
response3: bbbbbb
response4: 

the process being run looks like that:

s = sys.stdin.readline()
print s.upper()
s = sys.stdin.readline()
print s.lower()
like image 362
Berry Tsakala Avatar asked Nov 06 '10 08:11

Berry Tsakala


People also ask

Can you read and write to the same file in Java?

You can't open the same file to read and write at the same time. You have to open and save the file information in a data structure and then close it. Then you have to work with the data structure in memory and open the file to write results. And when you finish to write you should close it.

Can we read write a stream simultaneously in Java?

To write one specified character to an output stream, use the write method with one int parameter. The int parameter represents the character to write. We can use what we have learned to read from one file and simultaneously write to another, as demonstrated in Listing C.

How do you read from and write to disk files in Java?

And here are some classes you can use to write character data to a file: Writer: This is an abstract class to write the character streams. OutputStreamWriter: This class is used to write character streams and also convert them to byte streams. FileWriter: A class to actually write characters to the file.


2 Answers

ok, it was also my python's code fault, but opposite to @Jon's answer, there was an EXTRA newline (0xA0 to be exact, which isn't Windows' standard).

once i'm strip()ing the extra 0xA0 from the line i get from Java, python adds a single "normal" \n to Java on the way back, and things run smoothly.

for the completeness of the question and answer, here's a working Java code:

import java.io.*;
import java.util.*;

public class Main {

    public static BufferedReader inp;
    public static BufferedWriter out;

    public static void print(String s) {
    System.out.println(s);
    }

    public static String pipe(String msg) {
    String ret;

    try {
        out.write( msg + "\n" );
        out.flush();
        ret = inp.readLine();
        return ret;
    }
    catch (Exception err) {

    }
    return "";
    }



    public static void main(String[] args) {

    String s;
    String cmd = "c:\\programs\\python\\python.exe d:\\a.py";

    try {

        print(cmd);
        print(System.getProperty("user.dir"));
        Process p = Runtime.getRuntime().exec(cmd);

        inp = new BufferedReader( new InputStreamReader(p.getInputStream()) );
        out = new BufferedWriter( new OutputStreamWriter(p.getOutputStream()) );

        print( pipe("AAAaaa") );
        print( pipe("RoteM") );

        pipe("quit")
        inp.close();
        out.close();
    }

    catch (Exception err) {
        err.printStackTrace();
    }
    }
}

and this is the python code

import sys
s = sys.stdin.readline().strip()
while s not in ['break', 'quit']:
    sys.stdout.write(s.upper() + '\n')
    sys.stdout.flush()
    s = sys.stdin.readline().strip()
like image 128
Berry Tsakala Avatar answered Nov 15 '22 22:11

Berry Tsakala


I believe the problem is in the process you're calling:

s = sys.stdin.readline()
print s.upper()
s = sys.stdin.readline()
print s.lower()

I suspect that readline is going to read the line but s will not include the line terminator. You're then printing that line, but without a line terminator... Java is then blocking until it reads a line terminator, which will block forever as the process isn't giving one.

This is all a bit of a guess as it's not exactly clear to me what language your called process is in - if print actually does output a line terminator, then it's an incorrect guess. However, if not, you may need to change it to something like:

s = sys.stdin.readline()
println s.upper()
s = sys.stdin.readline()
println s.lower()

EDIT: That doesn't explain the blank lines in sample output... no idea what's going on, really, but unfortunately I can't look into it now.

like image 41
Jon Skeet Avatar answered Nov 15 '22 22:11

Jon Skeet