Как поместить данные из OutputStream в ByteBuffer? - PullRequest
20 голосов
/ 27 апреля 2010

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

Ответы [ 5 ]

32 голосов
/ 27 апреля 2010

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

21 голосов
/ 28 марта 2013

Существует более эффективный вариант ответа @ 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());

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

5 голосов
/ 09 мая 2014

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

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

1 голос
/ 27 апреля 2010

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

0 голосов
/ 06 ноября 2018

Вы говорите, что пишете в этот поток самостоятельно? Если это так, может быть, вы могли бы реализовать свой собственный ByteBufferOutputStream и plug n 'play.

Базовый класс будет выглядеть так:

public class ByteBufferOutputStream extends OutputStream {
    //protected WritableByteChannel wbc; //if you need to write directly to a channel
    protected static int bs = 2 * 1024 * 1024; //2MB buffer size, change as needed
    protected ByteBuffer bb = ByteBuffer.allocate(bs);

    public ByteBufferOutputStream(...) {
        //wbc = ... //again for writing to a channel
    }

    @Override
    public void write(int i) throws IOException {
        if (!bb.hasRemaining()) flush();
        byte b = (byte) i;
        bb.put(b);
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        if (bb.remaining() < len) flush();
        bb.put(b, off, len);
    }

    /* do something with the buffer when it's full (perhaps write to channel?)
    @Override
    public void flush() throws IOException {
        bb.flip();
        wbc.write(bb);
        bb.clear();
    }

    @Override
    public void close() throws IOException {
        flush();
        wbc.close();
    }
    /*
}
...