Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows Java子进程不支持';t设置为父级时输入或输出';s标准IO(命令提示符)_Java_Windows_Cmd - Fatal编程技术网

Windows Java子进程不支持';t设置为父级时输入或输出';s标准IO(命令提示符)

Windows Java子进程不支持';t设置为父级时输入或输出';s标准IO(命令提示符),java,windows,cmd,Java,Windows,Cmd,在Windows下,当从命令行启动程序时,我无法可靠地操作子进程的I/O。这是令人沮丧的,因为服务器使用控制台进行I/O是标准的。GUI很好,但我更喜欢使用命令行并保持简单。我注意到,当我从EclipseIDE执行服务器时,子进程I/O是正常的,但从命令行运行则完全不同。我无法读取或写入子进程,但该进程仍在运行。我在下面编写了一些测试代码来演示这个问题,我希望这个问题可以在另一台机器上重现,然后有希望从中得到解决方案。从Eclipse执行时,继承的I/O会按预期工作。但是,当从Windows命令

在Windows下,当从命令行启动程序时,我无法可靠地操作子进程的I/O。这是令人沮丧的,因为服务器使用控制台进行I/O是标准的。GUI很好,但我更喜欢使用命令行并保持简单。我注意到,当我从EclipseIDE执行服务器时,子进程I/O是正常的,但从命令行运行则完全不同。我无法读取或写入子进程,但该进程仍在运行。我在下面编写了一些测试代码来演示这个问题,我希望这个问题可以在另一台机器上重现,然后有希望从中得到解决方案。从Eclipse执行时,继承的I/O会按预期工作。但是,当从Windows命令提示符执行时,无法向子进程读取或写入任何内容。在这两种情况下,将子进程输出重定向到文件总是成功的,但输入仍然无法传递给子进程。如果这个问题已经有了解决方案,请链接页面

JRE/JDK实现:

>java -version
java version "1.7.0_01"
Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
Java HotSpot(TM) 64-Bit Server VM (build 21.1-b02, mixed mode)
考虑以下代码:

package com.comp8nerd4u2.io.test;

/*
 * These tests attempt to confirm what I'm experiencing under my build environment
 */

import java.io.File;
import java.io.IOException;

public final class PIOTest {

/** The command to run as a child process. The command itself isn't the test, but what you use to run this Java program is the test. */
private static final String[] COMMAND = {"cmd.exe", "/c", "echo This is a test. Feel free to change this."}; // Change this to just {"cmd.exe"} or some other program that accepts input and you'll see how frustrating this is
/** Controls how the test process is built */
private static final ProcessBuilder PB = new ProcessBuilder(COMMAND);
/** How long to allow the process to run before forcibly terminating it. */
private static final long PROCESS_TIMEOUT = 10000L;
private static final Runnable R = new TimedInterruptWorker(PROCESS_TIMEOUT);

private static int n = 0;

static {
    PB.redirectErrorStream(true);
}

private PIOTest() {}

public static void main(String[] args) {

    // ----- Begin Tests -----

    /*
     * Test #1: Let's test putting our command's output onto our standard I/O streams
     * Goal condition: Child process outputs expected output, and exits before the timeout. If child process expects input, it should accept entered input.
     * Known success factors: Parent process' standard I/O is piped to Eclipse. Tests would probably succeed with Netbeans as well
     * Known fail factors: Parent process' standard I/O is piped to Windows Command Prompt
     * Result under fail condition: Child process hangs if it fills up its output buffer or requests input, but exits on its own otherwise, unless it took longer than the timeout. 
     */
    PB.inheritIO();
    doTest();

    // Test #2: Let's test putting our command's output into a file
    PB.redirectOutput(new File("piotest.txt"));
    doTest();
}

/**
 * Performs the I/O test.
 */
private static void doTest() {
    n++;
    Process p = null;
    try {
        p = PB.start();
    } catch (IOException e) {
        e.printStackTrace();
        return;
    }
    try {
        Thread t = new Thread(R);
        t.setDaemon(true);
        t.start();
        System.out.format("[Test #%d] Child exited with status code %d\n", n, p.waitFor());
        t.interrupt();
    } catch (InterruptedException e) {
        p.destroy();
        System.out.format("[Test #%d] Child took longer than the timeout.\n", n);
    }
}

/**
 * Useful for sending interrupts after a certain amount of time has passed.
 * 
 * @author comp8nerd4u2
 */
private static final class TimedInterruptWorker implements Runnable {

    private long timeout = 0;
    private Thread target = null;

    public TimedInterruptWorker(long timeout) {
        this(timeout, Thread.currentThread());
    }

    public TimedInterruptWorker(long timeout, Thread target) {
        this.timeout = timeout;
        this.target = target;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(timeout);
        } catch (InterruptedException e) {
            return;
        }
        target.interrupt();
    }

}

}
更新:我修改了测试以在运行时接受任何命令,并将其上载到我的linux vps服务器。我从ssh会话运行它,所有子进程的I/O都可以轻松地读写。有一件事我注意到了。当我以子进程的形式打开一个交互式bashshell,然后将其输出重定向到一个文件时,我想CentOS停止了我的程序。或者我的程序崩溃了

[admin@comp8nerd4u2 piotest]$ java -jar piotest.jar
Enter command to run : bash
[admin@comp8nerd4u2 piotest]$ [Test #1] Child took longer than the timeout.

[1]+  Stopped                 java -jar piotest.jar
[admin@comp8nerd4u2 piotest]$

第一行是我键入的命令。第二行是生成的bashshell,但我从未在其中键入任何内容,因此我的程序在超时后将其杀死。它准备进行第二次测试,创建“piotest.txt”文件,然后崩溃或被操作系统停止。实际测试本身没有改变,只是测试现在允许您输入在运行时运行的命令。这在linux中可以正常工作,但在windows中不行。我希望了解Win32 API的人能够解释为什么该测试在windows中失败。

您看过这篇文章吗

在我看来,您需要在Windows上为输入/输出流提供服务。这篇文章是关于Runtime.exec的,但我敢打赌ProcessBuilder的本机代码非常相似,并且在Windows上存在相同类型的问题


我想,为什么在Windows上的Eclipse上可以这样做,是因为Eclipse代表您为流服务,以便在控制台视图中显示内容。

我知道我回答得晚了,但在找到答案之前我遇到了这个问题,我想让同一条船上的其他任何人都能进行一些搜索

这实际上是Windows的一个已知错误:

您可以通过自己重定向流来绕过它:

Process p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
   System.out.println(line);
}

p.waitFor();

br.close();

这在Windows上不起作用没有内在的原因,在我看来它像是Java 7运行时中的一个bug。你还在做这个吗?我可能有一个建议。解决方法是手动流式传输I/O。我认为JVM实现只是针对继承的I/O安装了错误。我认为不同实现的里程数会有所不同。OP明确要求现有的标准输入和输出由子进程继承,这意味着没有需要维护的I/O流。(该功能仅在Java7中添加,在撰写本文时,Java7并不存在。)