是否可以使用 Java 从 Python 获取控制台输出?以下是此类输出的示例:

Python 3.3.4 (v3.3.4:7ff62415e426, Feb 10 2014, 18:13:51) [MSC v.1600 64 bit (AMD64)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 2+2
4
>>>

现在,主要目标是通过使用 Java 调用 Python 解释器来获得上述输出。这是我的尝试:
//...
//Irrelevant code omitted

ProcessBuilder processBuilder = new ProcessBuilder("cmd");
processBuilder.redirectErrorStream(true);
processBuilder.start();
processBuilder.command("python2");
Process pythonProcess = processBuilder.start();
OutputStream outputStream = pythonProcess.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(outputStream);
osw.write("2+2\r\nquit()\r\n");
osw.flush();
osw.close();
InputStream inputStream = pythonProcess.getInputStream();
BufferedReader bufferedReader = new BufferedReader(
                  new InputStreamReader(inputStream));
String line;

while( (line=bufferedReader.readLine())!=null) {

    System.out.println(line);

}

//...
//Irrelevant code omitted

我知道调用 start 方法会产生一个新进程及其执行环境。将 python2 写入进程的输出流会导致创建另一个进程。这是问题开始的时候。我一直无法找到将命令 2+2 发送到 Python 解释器(它是 CMD 的子进程)而不是其父进程的方法。

总结一下:如何运行 Python 解释器,在其中执行一些命令,最后将结果打印到标准输出?

最佳答案

Python 可执行文件可以告诉您正在运行命令
非交互式。一旦它意识到它正在以非交互方式运行
将不再尝试与您互动;为什么要打印到
如果没有人,标准输出或从标准输入读取?

要确定这是真的,您将尝试运行例如"ls"或 "ps"和
看到它们在您的程序中工作,然后运行例如“ftp”或“telnet”
或“python”,看到它不起作用并且什么也不输出。

用 Linux 的话来说,问题在于我们运行的方式
进程不会将 TTY 附加到它们。解决办法就是骗他们
通过创建 PTY 相信另一端有 TTY。

Trick an application into thinking its stdin is interactive, not a pipe

上:

  • 我的 Mac OS X 10.9.4 笔记本电脑,带有 CPython 2.7.5 和 Java 1.8.0_05 和
  • 带有 CPython 2.7.5 和 Java 1.7.0_55 的 Ubuntu 12.04.4 LTS 服务器

  • 以下作品,虽然以一种非常丑陋的方式:

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    
    class Foo {
        public static void main(String[] args) throws IOException, InterruptedException {
            // https://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe
            //
            // Using script or unbuffer is the important catch. Without this
            // step you cannot use stdin in Python interactively, even with
            // python -u. At least script comes with Linux/Mac OS X, but
            // unbuffer works fine too.
            ProcessBuilder pb;
            switch(System.getProperty("os.name")) {
                case "Mac OS X":
                    pb = new ProcessBuilder(
                        "/usr/bin/script", "-q", "/dev/null", "/usr/bin/python");
                    break;
                default:
                    // Linux
                    pb = new ProcessBuilder(
                        "/usr/bin/script", "-qfc", "/usr/bin/python", "/dev/null");
    
            }
            // This doesn't make a difference.
            // pb.redirectErrorStream(true);
    
            Process p = pb.start();
    
            char[] readBuffer = new char[1000];
            InputStreamReader isr = new InputStreamReader(p.getInputStream());
            BufferedReader br = new BufferedReader(isr);
            int charCount;
            boolean written = false;
            while(true) {
                if (!br.ready() && !written) {
                    // Ugly. Should be reading for '>>>' prompt then writing.
                    Thread.sleep(1000);
                    if (!written) {
                        written = true;
                        OutputStream os = p.getOutputStream();
                        OutputStreamWriter osw = new OutputStreamWriter(os);
                        BufferedWriter bw = new BufferedWriter(osw);
                        bw.write("2+2");
                        bw.newLine();
                        bw.write("quit()");
                        bw.newLine();
                        bw.flush();
                        bw.close();
                    }
                    continue;
                }
                charCount = br.read(readBuffer);
                if (charCount > 0)
                    System.out.print(new String(readBuffer, 0, charCount));
                else
                    break;
            }
        }
    }
    

    我不会这样做。相反,我会使用线程来保持交互
    并避免阻塞读取并执行期望的操作,即等待
    写出之前的某些提示。在上面的代码中我盲目地 sleep
    然后希望最好。

    但是我注意到您使用的是 Windows,因为您已经运行了“cmd”。
    我不知道如何在 Windows 上创建 PTY,抱歉。我想虽然
    你可以得到 Expect for Windows; unbuffer 是一个实用程序
    预计:

    http://expect.sourceforge.net/

    或者尝试 cygwin,但我还没有测试过。

    有关 TTY 和 PTY 的更多背景信息,请参阅:

    How to create a pseudo-tty for reading output and writing to input

    关于java - 如何运行 Python 解释器并使用 Java 获取其输出?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25041529/

    10-14 16:05
    查看更多