Java 将InputStream复制到OutputStream将停止,除非我还写入System.out

Java 将InputStream复制到OutputStream将停止,除非我还写入System.out,java,inputstream,outputstream,Java,Inputstream,Outputstream,因此,我在Java内部运行了一个Python进程。我正在尝试将其输出复制到OutputStream。流程运行正常;但是,每当我尝试将进程#getInputStream()和进程#getErrorStream()复制到输出流时,程序都会挂起。 为了调试它,我添加了一个print语句,以便在每次迭代时输出缓冲区,如下所示: public static void copy(InputStream in, OutputStream out) throws IOException { byte[

因此,我在Java内部运行了一个Python进程。我正在尝试将其输出复制到OutputStream。流程运行正常;但是,每当我尝试将
进程#getInputStream()
进程#getErrorStream()
复制到输出流时,程序都会挂起。
为了调试它,我添加了一个print语句,以便在每次迭代时输出缓冲区,如下所示:

public static void copy(InputStream in, OutputStream out) throws IOException {

    byte[] buffer = new byte[4096];
    int n = 0;
    while ((n = in.read(buffer)) != -1) {
        // I have no clue why, but this only works if I print the output to sysdout
        System.out.println(new String(buffer));
        out.write(buffer, 0, n);
    }
}
出于某种奇怪的原因,这样做使一切都按预期进行。尝试刷新OutputStream、刷新System.out、或将空字符打印到标准输出、或事件打印普通
字节[]缓冲区
都不起作用,只有上面提到的才起作用

我的代码怎么会发生这种情况

编辑:显示用法

public int runModule(OutputStream moduleOut, int argShowRange, List<String> arguments) throws IOException {

    int status = -1;
    Logger logger = Util.getOutputStreamLogger(moduleOut);
    logger.info("Starting module {}", getModuleName());

    ProcessBuilder exec = new ProcessBuilder();
    exec.directory(getWorkingDirectory());
    if (configureEnvironment(exec.environment(), moduleOut)) {

        List<String> command = getExecutable();
        command.addAll(arguments);
        exec.command(command);

        LOGGER.info("With PYTHONPATH: {}", exec.environment().get("PYTHONPATH"));
        LOGGER.info("In: {}", getWorkingDirectory());
        LOGGER.info("Executing: {}", StringUtils.join(command, " "));
        Process proc = exec.start();
        LOGGER.info("Copying input stream");
        copy(proc.getInputStream(), moduleOut);

        try {
            logger.info("Waiting for process");
            status = proc.waitFor();
            if (status != 0) {
                logger.error("The process failed with the following error: ");
                copy(proc.getErrorStream(), moduleOut);
            }
            logger.info("The process finished with exit code: {}", status);
        } catch (InterruptedException e) {
            LOGGER.warn("The thread was interrupted", e);
            Thread.currentThread().interrupt();
        }
    } else {
        logger.info("Module configuration failed");
    }
    Util.detachOutputStreamFromLogger(logger);

    return status;
} 
public int runModule(OutputStream moduleOut、int argShowRange、List参数)引发IOException{
int status=-1;
Logger Logger=Util.getOutputStreamLogger(moduleOut);
info(“启动模块{}”,getModuleName());
ProcessBuilder exec=新的ProcessBuilder();
exec.directory(getWorkingDirectory());
if(configureEnvironment(exec.environment(),moduleOut)){
List命令=getExecutable();
addAll(参数);
执行命令(command);
info(“With PYTHONPATH:{}”,exec.environment().get(“PYTHONPATH”);
info(“In:{}”,getWorkingDirectory());
info(“正在执行:{}”,StringUtils.join(命令“”);
Process proc=exec.start();
LOGGER.info(“复制输入流”);
复制(proc.getInputStream(),moduleOut);
试一试{
logger.info(“等待处理”);
status=proc.waitFor();
如果(状态!=0){
logger.error(“进程失败,出现以下错误:”);
复制(proc.getErrorStream(),moduleOut);
}
info(“进程已完成,退出代码:{}”,状态);
}捕捉(中断异常e){
LOGGER.warn(“线程被中断”,e);
Thread.currentThread().interrupt();
}
}否则{
logger.info(“模块配置失败”);
}
Util.detachOutputStreamFromLogger(记录器);
返回状态;
} 

正如EJP建议的那样,我通过一个执行器将流的复制拆分为单独的线程,然后确保在生成的进程完成后关闭它们:

public int runModule(OutputStream moduleOut, int argShowRange, List<String> arguments) throws IOException {

    int status = -1;
    Logger logger = Util.getOutputStreamLogger(moduleOut);
    logger.info("Starting module {}", getModuleName());

    ProcessBuilder exec = new ProcessBuilder();
    exec.directory(getWorkingDirectory());
    if (configureEnvironment(exec.environment(), moduleOut)) {

        List<String> command = getExecutable();
        command.addAll(arguments);
        exec.command(command);

        logger.info("With PYTHONPATH: {}", exec.environment().get("PYTHONPATH"));
        logger.info("In: {}", getWorkingDirectory());
        logger.info("Executing: {}", StringUtils.join(command, " "));
        Process proc = exec.start();

        try (InputStream procOut = proc.getInputStream(); InputStream procErrOut = proc.getErrorStream()) {
            copy(procOut, moduleOut);
            copy(procErrOut, moduleOut);
            LOGGER.debug("Waiting for process to finish");
            status = proc.waitFor();
            LOGGER.debug("Closing streams");
            procOut.close();
            procErrOut.close();
            logger.info("The process finished with exit code: {}", status);
        } catch (InterruptedException e) {
            LOGGER.warn("The thread was interrupted", e);
            Thread.currentThread().interrupt();
        }
    } else {
        logger.info("Module configuration failed");
    }
    Util.detachOutputStreamFromLogger(logger);

    return status;
}

public void copy(final InputStream in, final OutputStream out) throws IOException {
    executor.execute(() -> {
        try {
            byte[] buffer = new byte[4096];
            int n = 0;
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
            }
        } catch (IOException e) {
            LOGGER.error("Ya done goofed", e);
        }
    });
}
public int runModule(OutputStream moduleOut、int argShowRange、List参数)引发IOException{
int status=-1;
Logger Logger=Util.getOutputStreamLogger(moduleOut);
info(“启动模块{}”,getModuleName());
ProcessBuilder exec=新的ProcessBuilder();
exec.directory(getWorkingDirectory());
if(configureEnvironment(exec.environment(),moduleOut)){
List命令=getExecutable();
addAll(参数);
执行命令(command);
info(“With PYTHONPATH:{}”,exec.environment().get(“PYTHONPATH”);
info(“In:{}”,getWorkingDirectory());
info(“正在执行:{}”,StringUtils.join(命令“”);
Process proc=exec.start();
试试(InputStream procOut=proc.getInputStream();InputStream procerout=proc.getErrorStream()){
拷贝(procOut,moduleOut);
复印件(原版、模版);
调试(“等待进程完成”);
status=proc.waitFor();
LOGGER.debug(“关闭流”);
procOut.close();
procErrOut.close();
info(“进程已完成,退出代码:{}”,状态);
}捕捉(中断异常e){
LOGGER.warn(“线程被中断”,e);
Thread.currentThread().interrupt();
}
}否则{
logger.info(“模块配置失败”);
}
Util.detachOutputStreamFromLogger(记录器);
返回状态;
}
公共无效副本(最终输入流输入,最终输出流输出)引发IOException{
执行者。执行(()->{
试一试{
字节[]缓冲区=新字节[4096];
int n=0;
而((n=in.read(buffer))!=-1){
out.write(缓冲区,0,n);
}
}捕获(IOE异常){
记录器错误(“你搞错了”,e);
}
});
}

这甚至不太可能。你在同一时间修复了其他东西。注意:它应该是
新字符串(缓冲区,0,n)
,或者
系统输出写入(缓冲区,0,n)
。只要没有输入,复制循环就会阻塞。您是否关闭了he流程的输入流?您正在使用它的标准错误流吗?@EJP我正在使用它来使用标准错误流和标准输出流。在从流中复制之后,我调用
进程#waitFor()
,但是执行从未达到这一点。我将更新问题以显示我是如何使用它的。1。您尚未关闭进程的输入流。2.您需要合并输出流和错误流,或者在单独的线程中同时使用它们。3.
moduleOut
连接到什么?@EJP它连接到
HttpServletResponse
You的输出流;我只谈了三点中的一点。上次你也做了同样的事。我厌倦了重复我自己。