当前位置: 首页 > 面试题库 >

运行子流程,使用Java正确地为其提供输入和输出

沃弘图
2023-03-14
问题内容

我使用运行时exec()方法在Java中创建一个子进程。但是,由于子流程是一个交互式程序,因此我需要在需要时向其提供输入。另外,我需要显示子流程的输出。如何以最简单的方式做到这一点?

我正在使用StreamGobbler通过process.getInputStream()显示程序输出。但是,我不知道如何识别程序何时等待输入以及何时使用proc.getOutputStream提供输入。我怎样才能做到这一点?


问题答案:

你需要复制子流之间的输入和输出System流(System.inSystem.outSystem.err)。这与我最近的疑问有关。到目前为止,我发现的最佳解决方案是:

import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.FileChannel;

class StreamCopier implements Runnable {
    private InputStream in;
    private OutputStream out;

    public StreamCopier(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n;
            byte[] buffer = new byte[4096];
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
                out.flush();
            }
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

class InputCopier implements Runnable {
    private FileChannel in;
    private OutputStream out;

    public InputCopier(FileChannel in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n;
            ByteBuffer buffer = ByteBuffer.allocate(4096);
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer.array(), 0, n);
                out.flush();
            }
            out.close();
        }
        catch (AsynchronousCloseException e) {}
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

public class Test {
    private static FileChannel getChannel(InputStream in)
            throws NoSuchFieldException, IllegalAccessException {
        Field f = FilterInputStream.class.getDeclaredField("in");
        f.setAccessible(true);
        while (in instanceof FilterInputStream)
            in = (InputStream)f.get((FilterInputStream)in);
        return ((FileInputStream)in).getChannel();
    }

    public static void main(String[] args)
            throws IOException, InterruptedException,
                   NoSuchFieldException, IllegalAccessException {
        Process process = Runtime.getRuntime().exec("sh -i +m");
        Thread outThread = new Thread(new StreamCopier(
                process.getInputStream(), System.out));
        outThread.start();
        Thread errThread = new Thread(new StreamCopier(
                process.getErrorStream(), System.err));
        errThread.start();
        Thread inThread = new Thread(new InputCopier(
                getChannel(System.in), process.getOutputStream()));
        inThread.start();
        process.waitFor();
        System.in.close();
        outThread.join();
        errThread.join();
        inThread.join();
    }
}

这里最棘手的部分是从中提取频道System.in。否则,子进程终止时,您将无法中断读取输入的线程。

这种方法有一个严重的缺点:关闭后,System.in您将无法再读取它。我当前正在使用的解决方法是为所有子流程使用一个输入重定向线程。



 类似资料:
  • 我想在提取一些数据时使用外部工具(循环通过行)。为此,我首先使用了Runtime.getRuntime()。exec()执行它。但后来我的提取变得很慢。所以我在寻找一种可能性,在循环的每个实例中,使用shell的同一个实例来执行外部工具。 我发现,我应该使用ProcessBuilder。但是现在还不行。 这是我测试执行的代码(已经从论坛中的答案输入): 我想在另一个类中调用它,例如 Testcla

  • 问题内容: 我下面有以下代码示例。你可以在其中输入的命令,即回显结果。但是,先读后。其他输出流不起作用? 为什么会这样或我做错了什么?我的最终目标是创建一个线程计划任务,该任务定期执行对/ bash的命令,因此必须一前一后工作,而不能停止工作。我也一直在经历错误的任何想法? 谢谢。 问题答案: 首先,我建议更换生产线 与线 ProcessBuilder是Java 5中的新增功能,它使运行外部进程更

  • 问题内容: 我有要在Java程序中运行的rsync命令…我面临的问题是rsync需要输入密码,而我不了解如何将此密码传递给rsync命令才能工作? 问题答案: 我将发布此代码示例: 但是维尼特·雷诺兹领先于我。 正如Vineet Reynolds指出的那样,使用这种方法将需要另外一段代码来检测rsync何时需要密码。因此,使用外部密码文件似乎是一种更简单的方法。 PS:可能存在与编码有关的问题,可

  • 本小节将会介绍基本输入输出的 Java 标准类,通过本小节的学习,你将了解到什么是输入和输入,什么是流;输入输出流的应用场景,File类的使用,什么是文件,Java 提供的输入输出流相关 API 等内容。 1. 什么是输入和输出(I / O) 1.1 基本概念 输入/输出这个概念,对于计算机相关专业的同学并不陌生,在计算中,输入/输出(Input / Output,缩写为 I / O)是信息处理系

  • 我的应用程序实现了VpnService来拦截流量并提供量身定制的响应。目标是处理到特定地址的流量,并丢弃其他请求。 目前,我成功地解析了传入的请求,构建并发送了响应。然而,问题是这些响应并不是对原始请求的实际响应;使用套接字连接进行测试只是超时。 为了进行这一区分,我目前正在解析VPN服务输入流中的原始IP数据包,如下所示: IpDatagram是一个类,通过它可以将字节数组解析为IP数据包的表示