Можно ли прочитать стандартный вывод 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())
Я не вижу здесь, как вы получаете вывод за пределы runnable, но я подозреваю, что ваш исходный код имел это. В противном случае вы можете захотеть, чтобы StreamConsumer
был Callable<ByteBuffer>
.
Другие советы
Я создал библиотеку с открытым исходным кодом, которая позволяет неблокировать ввод-вывод между Java и вашими дочерними процессами. Библиотека предоставляет управляемую событиями модель обратного вызова. Использование библиотеки JNA для конкретной платформы зависит от библиотеки JNA, такой как epoll в Linux, kqueue / kevent в MacOS X или порты завершения ввода-вывода в Windows.
Проект называется NuProcess и его можно найти здесь:
вы можете захотеть, чтобы StreamConsumer был вызываемым.
Еще одна неблокирующая опция, которую можно попробовать, может заключаться в использовании ListenableFuture от Guava, обеспечивающем успешные и неудачные обратные вызовы без интерпретации собственных ошибок.