能否将进程的标准输出流读入NIO ByteBuffer中?

7

是否可以使用NIO处理进程的标准输出?我已经使用java.io实现了它,但这是为了更好地了解NIO并探索性能提升的可能性而进行的练习。

基本上,我想尽可能快地将大量文本从stdout流式传输到缓冲区中,而不会阻塞,然后稍后处理该缓冲区的内容。问题是,我似乎无法找到正确的方法来使用NIO实现。目前我的进展如下:

ProcessBuilder pb = new ProcessBuilder( ... );
Process p = pb.start();
stdout = new StreamConsumer(p.getInputStream());
new Thread(stdout).start();
// other stuff omitted for brevity

StreamConsumer类如下所示:

class StreamConsumer implements Runnable
{
  private InputStream is;

  public StreamConsumer(InputStream is)
  {
    this.is = is;
  }

  public void run()
  {
    try
    {
      ReadableByteChannel source = Channels.newChannel(is);

      // Is it possible get a channel to a ByteBuffer 
      // or MappedByteBuffer here?
      WritableByteChannel destination = ??;
      ByteBuffer buffer = ByteBuffer.allocateDirect(128 * 1024);

      while (source.read(buffer) != -1)
      {
        buffer.flip();
        while (buffer.hasRemaining())
        {
          destination.write(buffer);
        }
        buffer.clear();
      }

      source.close();
      destination.close();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }
}

您想简单地将所有标准输入一次性放入单个字节缓冲区中吗?您知道输入流的最大长度吗? - Matthew Flaschen
我想一次性将其读入缓冲区,但长度未知;通常在10 MB范围内。 - Rob
3个回答

10
我创建了一个开源库,允许Java与您的子进程之间进行非阻塞I/O。该库提供了一个事件驱动的回调模型。它依赖于JNA库来使用特定于平台的本机API,例如Linux上的epoll,MacOS X上的kqueue/kevent或Windows上的IO完成端口。
该项目称为NuProcess,可以在此处找到:

https://github.com/brettwooldridge/NuProcess


5

信不信由你,我认为你需要的可写字节通道是

ByteArrayOutputStream ostream = new ByteArrayOutputStream(<some large number>);
WritableByteChannel destination = Channels.newChannel(ostream);

然后完成时。
ostream.toByteArray() 

包含要处理的字节。或者,如果您想要一个字节缓冲区,

ByteBuffer.wrap(ostream.toByteArray())

我在这里看不到如何在可运行的区域之外获取输出,但我猜测您的原始代码有这样的操作。否则,您可能希望将StreamConsumer设置为Callable<ByteBuffer>


1
使用Callable的建议非常好。我简直不敢相信我忘了它。这个方法非常有效。 - Rob

1

你可能希望将StreamConsumer设为可调用的。

另一个非阻塞的选择是尝试使用Guava的ListenableFuture,它可以给你成功和失败的回调,而无需解释自己的错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接