Issue in calling Python code from Java (without using jython)
Asked Answered
A

3

6

I found this as one of the ways to run (using exec() method) python script from java. I have one simple print statement in python file. However, my program is doing nothing when I run it. It neither prints the statement written in python file nor throws an exception. The program just terminates doing nothing:

Process p = Runtime.getRuntime().exec("C:\\Python\\Python36-32\\python.exe C:\\test2.py");

Even this is not creating the output file:

Process p = Runtime.getRuntime().exec("C:\\Python\\Python36-32\\python.exe C:\\test2.py output.txt 2>&1");

What is the issue?

Amabel answered 25/1, 2019 at 5:0 Comment(2)
If you manually type that exact string in using the Windows command shell program cmd.exe does it do what you'd expect?Kanal
Yes, both the statements give the results as expected.Amabel
J
2

I think you could try your luck with the ProcessBuilder class.

If I read the Oracle documentation correctly, the std inputs and outputs are directed to pipes by default but the ProcessBuilder has an easy method for you to explicitly set output (or input) to a file on your system or something else.

If you want your Python program to use the same output as your Java program (likely stdout and stderr), you can use stg like this:

ProcessBuilder pb = new ProcessBuilder("C:\\Python\\Python36-32\\python.exe", "C:\\test2.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
Janeanjaneczka answered 25/1, 2019 at 5:18 Comment(4)
Am getting this error: java.io.IOException: Cannot run program "C:\Python\Python36-32\python.exe C:\test2.py": CreateProcess error=2, The system cannot find the file specified at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048) at RunninPythonFromJava.main(RunninPythonFromJava.java:16) Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specifiedAmabel
How about this: https://mcmap.net/q/246455/-createprocess-error-2-the-system-cannot-find-the-file-specified ? Does that solve your problem ?Janeanjaneczka
This worked like a charm - ProcessBuilder pb = new ProcessBuilder("C:\\Python\\Python36-32\\python.exe", "C:\\test2.py");. Going further, how can I pass the arguments to python and get the return data?Amabel
You can pass arguments just as would on a terminal, by adding them to your command line in your code: ... new ProcessBuilder("C:\Python\\Python36-32\\python.exe", "C:\\test2.py", "arg0", "arg1"); Or do you want to have some sort of interaction between your Java program and your Python program ? In which case you could make your Java program write some stuff to the input stream of your python process. As for the return data I do not know what it is you are doing. One thing you could do is make Java read what your python program outputs on stdout but that seems quite annoying to do to me.Janeanjaneczka
M
2

You can use the ProcessBuilder API, redirecting the output to a file and then wait for the result.

public class Main {

    public static final String PYTHON_PATH = "D:\\Anaconda3\\python.exe";
    public static final String PATH_TO_SCRIPT = "D:\\projects\\StartScript\\test.py";

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder builder = new ProcessBuilder();
        builder.command(PYTHON_PATH, PATH_TO_SCRIPT);

        // Redirect output to a file
        builder.redirectOutput(new File("output.txt"));

        builder.start().waitFor();

        // Print output to console
        ProcessBuilder.Redirect output = builder.redirectOutput();
        File outputFile = output.file();
        BufferedReader br = new BufferedReader(new FileReader(outputFile));

        String st;
        while ((st = br.readLine()) != null) {
            System.out.println(st);
        }

    }
}

The python file test.py contains a simple print statement:

print("Hello from python")

I guess it would be even simpler, if you do not need to wait for the result.

Using the Process API should work, too.

Like in your example (I am using the same constants declared above):

Process p = Runtime.getRuntime().exec(PYTHON_PATH + " " + PATH_TO_SCRIPT);
p.waitFor();

byte[] buffer = new byte[1024];
byte[] errBuffer = new byte[1024];

p.getInputStream().read(buffer);
p.getErrorStream().read(errBuffer);

System.out.println(new String(buffer));
System.out.println(new String(errBuffer));

To see the output of the print statement, you need to wait and redirect the streams. Same for the error stream.

Now if you break the python script like this:

print("Hello from python')

you should be able to see the error printed as well.

Mast answered 25/1, 2019 at 9:8 Comment(0)
S
1

One way to start a python process is using an entrypoint - test.cmd

echo Hello
python hello.py

here is hello.py

#!/usr/bin/env python3
import os
if not os.path.exists('dir'):
    os.makedirs('dir')

Here is my Java code:

public static void main(String[] args) throws IOException {
    try {
        Process p = Runtime.getRuntime().exec("test.cmd");
        p.waitFor();
        Scanner sc = new Scanner(p.getInputStream());
        while(sc.hasNextLine()){
            System.out.println(sc.nextLine());
        }
        sc.close();
    } catch (Exception err) {
        err.printStackTrace();
    }
}
Stake answered 25/1, 2019 at 8:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.