Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.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
如何从java.lang.Process关闭std流?_Java_Process_Stream_Resources - Fatal编程技术网

如何从java.lang.Process关闭std流?

如何从java.lang.Process关闭std流?,java,process,stream,resources,Java,Process,Stream,Resources,这个问题是关于java.lang.Process及其对stdin、stdout和stderr的处理 我们的项目中有一个类,它是org.apache.commons.io.IOUtils的扩展。我们有一个安静的新方法来关闭进程对象的std流?还是不合适 /** * Method closes all underlying streams from the given Process object. * If Exit-Code is not equal to 0 then Process wi

这个问题是关于
java.lang.Process
及其对stdin、stdout和stderr的处理

我们的项目中有一个类,它是org.apache.commons.io.IOUtils的扩展。我们有一个安静的新方法来关闭进程对象的std流?还是不合适

/**
 * Method closes all underlying streams from the given Process object.
 * If Exit-Code is not equal to 0 then Process will be destroyed after 
 * closing the streams.
 *
 * It is guaranteed that everything possible is done to release resources
 * even when Throwables are thrown in between.
 *
 * In case of occurances of multiple Throwables then the first occured
 * Throwable will be thrown as Error, RuntimeException or (masked) IOException.
 *
 * The method is null-safe.
 */
public static void close(@Nullable Process process) throws IOException {
    if(process == null) {
      return;
    }

    Throwable t = null;

    try {
      close(process.getOutputStream());
    }
    catch(Throwable e) {
      t = e;
    }

    try{
      close(process.getInputStream());
    }
    catch(Throwable e) {
      t = (t == null) ? e : t;
    }

    try{
      close(process.getErrorStream());
    }
    catch (Throwable e) {
      t = (t == null) ? e : t;
    }

    try{
      try {
        if(process.waitFor() != 0){
          process.destroy();
        }
      }
      catch(InterruptedException e) {
        t = (t == null) ? e : t;
        process.destroy();
      }
    }
    catch (Throwable e) {
      t = (t == null) ? e : t;
    }

    if(t != null) {
      if(t instanceof Error) {
        throw (Error) t;
      }

      if(t instanceof RuntimeException) {
        throw (RuntimeException) t;
      }

      throw t instanceof IOException ? (IOException) t : new IOException(t);
    }
}


类似的方法基本上用于finally块

我真正想知道的是,我使用这个实现是否安全?考虑以下情况:进程对象在其生命周期内是否总是返回相同的stdin、stdout和stderr流?或者我可能会错过关闭以前由进程“
getInputStream()
getOutputStream()
getErrorStream()
方法返回的流吗

StackOverflow.com上有一个相关问题:

编辑

正如我和其他人在这里指出的那样:

  • 必须完全消耗输入流。如果未完成,则子流程可能不会终止,因为其输出流中存在未完成的数据
  • 所有三个std流都必须关闭。无论之前是否使用过
  • 当子流程正常终止时,一切正常。如果没有,则必须强制终止
  • 当子流程返回退出代码时,我们不需要销毁它。它已经终止。(即使不一定以退出代码0正常终止,但它已终止。)
  • 我们需要监视
    waitFor()
    并在超时超过时中断,以使进程有机会正常终止,但在挂起时终止它
未回答的部分:

  • 考虑并行使用输入流的利弊。还是必须按特定顺序食用

    • 简化代码的尝试:

      public static void close(@Nullable Process process) throws IOException
      {
          if(process == null) { return; }
      
          try
          {
              close(process.getOutputStream());
              close(process.getInputStream());
              close(process.getErrorStream());
      
              if(process.waitFor() != 0)
              {
                  process.destroy();
              }
          }
          catch(InterruptedException e)
          {
              process.destroy();
          }
          catch (RuntimeException e)
          {
              throw (e instanceof IOException) ? e : new IOException(e);
          }
      }
      
      通过捕获可丢弃的
      Throwable
      我假设您希望捕获所有未检查的异常。这是
      运行时异常
      错误
      的派生。但是
      错误
      永远不应该被捕获,所以我用
      运行时异常
      替换了
      可丢弃的


      (捕获所有的
      运行时异常仍然不是一个好主意。)

      作为链接到状态的问题,最好读取并丢弃输出和错误流。如果您使用的是apache commons io

      new Thread(new Runnable() {public void run() {IOUtils.copy(process.getInputStream(), new NullOutputStream());}}).start();
      new Thread(new Runnable() {public void run() {IOUtils.copy(process.getErrorStream(), new NullOutputStream());}}).start();
      
      您希望在一个单独的线程中读取和丢弃stdout和stderr,以避免在将足够的信息写入stderr或stdout以填充缓冲区时出现诸如进程阻塞之类的问题

      如果您担心有两个多线程,请参见此

      我认为在将stdout、stdin复制到NullOutputStream时,您不必担心捕捉IOException,因为如果从进程stdout/stdin读取IOException,可能是由于进程本身已死亡,写入NullOutputStream将永远不会引发异常

      您不需要检查waitFor()的返回状态

      是否要等待进程完成?如果是的话,你可以这样做

      while(true) {
           try
           {
               process.waitFor();
               break;
           } catch(InterruptedException e) {
               //ignore, spurious interrupted exceptions can occur
           }
      
      }
      
      查看您提供的链接,您确实需要在流程完成时关闭流,但destroy将为您完成此操作

      所以最后,这个方法变成

      public void close(Process process) {
      
          if(process == null) return;
      
          new Thread(new Runnable() {public void run() {IOUtils.copy(process.getInputStream(), new NullOutputStream());}}).start();
          new Thread(new Runnable() {public void run() {IOUtils.copy(process.getErrorStream(), new NullOutputStream());}}).start();
          while(true) {
              try
              {
                  process.waitFor();
                  //this will close stdin, stdout and stderr for the process
                  process.destroy();
                  break;
              } catch(InterruptedException e) {
                  //ignore, spurious interrupted exceptions can occur
              }
      
         }
      }
      

      只是想让您知道我目前在我们的代码库中拥有什么:

      public static void close(@Nullable Process process) throws IOException {
        if (process == null) {
          return;
        }
      
        Throwable t = null;
      
        try {
          flushQuietly(process.getOutputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          close(process.getOutputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          skipAllQuietly(null, TIMEOUT, process.getInputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          close(process.getInputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          skipAllQuietly(null, TIMEOUT, process.getErrorStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          close(process.getErrorStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          try {
            Thread monitor = ThreadMonitor.start(TIMEOUT);
            process.waitFor();
            ThreadMonitor.stop(monitor);
          }
          catch (InterruptedException e) {
            t = mostImportantThrowable(t, e);
            process.destroy();
          }
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        if (t != null) {
          if (t instanceof Error) {
            throw (Error) t;
          }
      
          if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
          }
      
          throw t instanceof IOException ? (IOException) t : new IOException(t);
        }
      }
      

      skipall(…)
      使用完整的输入流。它在内部使用一个类似于
      org.apache.commons.io.ThreadMonitor
      的实现,在超过给定超时时中断使用

      mostImportantThrowable(…)
      决定应返回哪些Throwable。一切都是错误。第一次发生的prio高于第二次发生的prio。这里没有什么很重要的,因为这些一次性的东西很可能会在以后被丢弃。我们想继续在这里工作,我们只能扔一个,所以我们必须决定最后扔什么,如果有的话


      close(…)
      是空安全的实现,用于关闭内容,但在出现问题时引发异常。

      请注意。您的代码中有一些严重的反模式。1.几乎每一条语句都要尝试/捕捉。2.每次都捕捉到所有“可丢弃”的东西。3.嵌套的try语句也可以是一个,有两个catch语句。如果不将其他流放入单独的try-catch块中,如何继续关闭其他流?必须使用嵌套的try-catch块,因为嵌套的catch块中可能会出现Throwable。对于可丢弃的捕获
      :什么更合适?我想抓住一切值得继续努力的东西,尽我最大的努力。当我以前被抓住时,我会在最后扔一个一次性的。在这里我能做得更好的是什么?请注意,这里是一个实用程序类,用于关闭其他地方的finally块中的资源。处理异常不是它的职责。它抛出第一个发生的异常。打电话的人必须处理这件事。但它的目的是尽一切可能释放调用者提供的资源。当关闭outputstream之前发生异常时,您的代码不会尝试关闭inputstream。捕获可丢弃性的目的是提供尽可能高的保证,以便在关闭资源的情况下继续工作。如果发生了丢弃,则在最后抛出第一个出现的丢弃。之所以这样做,是因为如果出现问题,它很可能是你想要的一次性物品。在这种情况下,为什么不抓住一次性的呢?我应该捕捉异常吗?为什么?
      IOException
      不能是
      RuntimeException
      。所以最后一个catch块的代码可以简化。但您的实现并没有尽全力关闭流。当catch interruptedException块中发生此异常时,它可能会抛出除
      IOException
      之外的其他异常+无论如何,因为至少有人考虑过。非常感谢你的回答。快速阅读
      public void close(Process process) {
      
          if(process == null) return;
      
          new Thread(new Runnable() {public void run() {IOUtils.copy(process.getInputStream(), new NullOutputStream());}}).start();
          new Thread(new Runnable() {public void run() {IOUtils.copy(process.getErrorStream(), new NullOutputStream());}}).start();
          while(true) {
              try
              {
                  process.waitFor();
                  //this will close stdin, stdout and stderr for the process
                  process.destroy();
                  break;
              } catch(InterruptedException e) {
                  //ignore, spurious interrupted exceptions can occur
              }
      
         }
      }
      
      public static void close(@Nullable Process process) throws IOException {
        if (process == null) {
          return;
        }
      
        Throwable t = null;
      
        try {
          flushQuietly(process.getOutputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          close(process.getOutputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          skipAllQuietly(null, TIMEOUT, process.getInputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          close(process.getInputStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          skipAllQuietly(null, TIMEOUT, process.getErrorStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          close(process.getErrorStream());
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        try {
          try {
            Thread monitor = ThreadMonitor.start(TIMEOUT);
            process.waitFor();
            ThreadMonitor.stop(monitor);
          }
          catch (InterruptedException e) {
            t = mostImportantThrowable(t, e);
            process.destroy();
          }
        }
        catch (Throwable e) {
          t = mostImportantThrowable(t, e);
        }
      
        if (t != null) {
          if (t instanceof Error) {
            throw (Error) t;
          }
      
          if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
          }
      
          throw t instanceof IOException ? (IOException) t : new IOException(t);
        }
      }