2010-04-26 4 views
20

В Java мне нужно поместить содержимое из OutputStream (я сам заполняю данные в этот поток) в ByteBuffer. Как это сделать простым способом?Как поместить данные из OutputStream в ByteBuffer?

+1

Как правило, вы не можете читать напрямую из потока вывода. Если вы сами заполняете данные, почему бы вам не заполнить его в ByteBuffer? –

+0

Это можно косвенно и непосредственно из него прочитать, если вы создаете класс, который наследует форму OutputStream и позволяет читать с нее напрямую. Я сам не заполнял данные, некоторые рамки (и код рамки, который я не хочу прикоснуться к причине). См. Также мои комментарии и ответы. – drasto

ответ

30

Вы можете создать ByteArrayOutputStream и написать ему и извлечь содержимое в виде byte[], используя toByteArray(). Затем ByteBuffer.wrap(byte []) создаст ByteBuffer с содержимым выходного массива байтов.

+0

Это именно то, что я сделал незадолго до того, как прочитал ваш комментарий. Поэтому я могу утверждать, что это работает :)) – drasto

+5

К сожалению, 'ByteArrayOutputStream # toByteArray()' делает копию базового байтового массива, поэтому, хотя этот рецепт прост, он не так эффективен, как нам бы хотелось. Однако, поскольку «ByteBuffer» фиксирован в емкости, желание записать произвольное количество данных через «OutputStream» в 'ByteBuffer' непримиримо. – seh

+0

@seh Это не должно быть так - см. Мой ответ. – mark

1

Попробуйте использовать PipedOutputStream вместо OutputStream. Затем вы можете подключить PipedInputStream для чтения данных из PipedOutputStream.

+0

Выглядит хорошо. Аналогичное мнение можно сделать с ByteArrayOutputStream, вызвав его метод newInputStream. Тем не менее, существует более сложное решение - обернуть массив, который напрямую поддерживает ByteArrayOutputStream в ByteBuffer. Это то, что я сделал. – drasto

18

Существует более эффективный вариант ответа @ DJClayworth.

Как @seh правильно заметили, ByteArrayOutputStream.toByteArray() возвращает копию объекта подложки byte[], который может быть неэффективным. Однако объект поддержки byte[], а также количество байтов являются защищенными членами класса ByteArrayOutputStream. Таким образом, вы можете создать свой собственный вариант ByteArrayOutputStream подвергая их непосредственно:

public class MyByteArrayOutputStream extends ByteArrayOutputStream { 
    public MyByteArrayOutputStream() { 
    } 

    public MyByteArrayOutputStream(int size) { 
    super(size); 
    } 

    public int getCount() { 
    return count; 
    } 

    public byte[] getBuf() { 
    return buf; 
    } 
} 

Используя этот класс легко:

MyByteArrayOutputStream out = new MyByteArrayOutputStream(); 
fillTheOutputStream(out); 
return new ByteArrayInputStream(out.getBuf(), 0, out.getCount()); 

В результате, когда все выходные данные записываются тот же буфер используется как основу входного потока.

+3

Хорошая точка, @mark. У меня есть такой класс в нескольких моих Java-проектах, обычно ограниченный как пакетно-частный класс под названием «PromiscuousByteArrayOutputStream». Имя преднамеренно длинное и зловещее. – seh

+1

getCount() не требуется, поскольку ByteArrayOutputStream.size() возвращает count. –

4

Несмотря на то, что вышеупомянутые ответы решают вашу проблему, ни одна из них не эффективна, как вы ожидаете от NIO. ByteArrayOutputStream или MyByteArrayOutputStream сначала записывают данные в память кучи Java, а затем копируют их в ByteBuffer, что существенно влияет на производительность.

Эффективная реализация будет писать класс ByteBufferOutputStream самостоятельно. На самом деле это довольно легко сделать. Вы должны просто предоставить метод write(). См. Эту ссылку для ByteBufferInputStream.

+0

, так как нам может понадобиться повторно использовать существующий ByteBuffer (и его базовый массив) для OutputStream вместо выделения нового массива для получения нового ByteBuffer, я считаю, что этот ответ более приемлем. – Ambling

Смежные вопросы