Process stdout InputStreamをNIO ByteBufferに読み込むことは可能ですか?
-
06-07-2019 - |
質問
NIOを使用してプロセスから標準出力を処理することは可能ですか?私はjava.ioで動作するようにしていますが、これはNIOについてもう少し学び、パフォーマンスの改善の可能性を調べるための演習です。
基本的には、大量のテキストを標準出力からブロックせずにできるだけ速くバッファにストリーミングしてから、そのバッファの内容を後で処理したいです。問題は、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();
}
}
}
解決
信じるかどうか、あなたが望む書き込み可能なバイトチャネルは
ByteArrayOutputStream ostream = new ByteArrayOutputStream(<some large number>);
WritableByteChannel destination = Channels.newChannel(ostream);
その後、完了
ostream.toByteArray()
には処理するバイトが含まれます。または、バイトバッファーが必要な場合は、
ByteBuffer.wrap(ostream.toByteArray())
ここでは、実行可能ファイルの外部で出力を取得する方法はわかりませんが、元のコードにはそれがあると思われます。そうでない場合は、StreamConsumer
をCallable<ByteBuffer>
にしたい場合があります。
他のヒント
Javaと子プロセス間の非ブロッキングI / Oを可能にするオープンソースライブラリを作成しました。このライブラリは、イベント駆動型のコールバックモデルを提供します。 Linuxのepoll、MacOS Xのkqueue / kevent、WindowsのIO完了ポートなど、プラットフォーム固有のネイティブAPIを使用するのはJNAライブラリに依存しています。
プロジェクトの名前は NuProcess であり、次の場所にあります。
StreamConsumerをCallableにしたい場合があります。
別の非ブロッキングオプションとして、GuavaのListenableFutureを使用して、独自のエラーを解釈せずに成功および失敗のコールバックを提供することもできます。