4

I have the following short python program "test.py"

n = int(raw_input())
print n

I'm executing the above program from following java program "ProcessRunner.java"

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

public class ProcessRunner {
    public static void main(String[] args) {
        try {
            Scanner s = new Scanner(Runtime.getRuntime().exec("python test.py").getInputStream()).useDelimiter("\\A");
            System.out.println(s.next());
        }

        catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

Upon running the command,

java ProcessRunner

I'm not able to pass a value 'n' in proper format to Python program and also the java run hangs. What is the proper way to handle the situation and pass a value to 'n' dynamically to python program from inside java program?

Sai Nikhil
  • 1,237
  • 2
  • 15
  • 39
  • Have a look here http://stackoverflow.com/questions/18903549/writing-to-inputstream-of-a-java-process for information on how to communicate with the python process. – Ilja Everilä Sep 21 '16 at 09:54
  • 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. – Andrew Thompson Sep 21 '16 at 11:10

2 Answers2

3

raw_input(), or input() in Python 3, will block waiting for new line terminated input on standard input, however, the Java program is not sending it anything.

Try writing to the Python subprocess using the stream returned by getOutputStream(). Here's an example:

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

public class ProcessRunner {
    public static void main(String[] args) {
        try {
            Process p = Runtime.getRuntime().exec("python test.py");
            Scanner s = new Scanner(p.getInputStream());
            PrintWriter toChild = new PrintWriter(p.getOutputStream());

            toChild.println("1234");    // write to child's stdin
            toChild.close();            // or you can use toChild.flush()
            System.out.println(s.next());
        }

        catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

An alternative is to pass n as a command line argument. This requires modification of the Python script to expect and process the command line arguments, and to the Java code to send the argument:

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

public class ProcessRunner {
    public static void main(String[] args) {
        try {
            int n = 1234;
            Process p = Runtime.getRuntime().exec("python test.py " + n);
            Scanner s = new Scanner(p.getInputStream());
            System.out.println(s.next());
        }

        catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

And the Python script, test.py:

import sys

if len(sys.argv) > 1:
    print int(sys.argv[1]) 
mhawke
  • 84,695
  • 9
  • 117
  • 138
0

If I understand you correctly you want your java program to pass any output from your python script to System.out and any input into your java program to your python Script, right?

Have a look at the following program to get an idea how you could do this.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ProcessRunner {

    public static void main(String[] args) {
        try {
            final Process process = Runtime.getRuntime().exec("/bin/sh");

            try (
                    final InputStream inputStream = process.getInputStream();
                    final InputStream errorStream = process.getErrorStream();
                    final OutputStream outputStream = process.getOutputStream()
            ) {

                while (process.isAlive()) {
                    forwardOneByte(inputStream, System.out);
                    forwardOneByte(errorStream, System.err);
                    forwardOneByte(System.in, outputStream);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void forwardOneByte(final InputStream inputStream,
                                       final OutputStream outputStream)
    throws IOException {
        if(inputStream.available() <= 0) {
            return;
        }

        final int b = inputStream.read();
        if(b != -1) {
            outputStream.write(b);
            outputStream.flush();
        }
    }
}

Note This code is just a concept demo. It will eat up your cpu and will not be able to cope with bigger amounts of throughput.

DaImmi
  • 121
  • 5