How to put data from an OutputStream into a ByteBuffer?

后端 未结 6 1859
庸人自扰
庸人自扰 2021-02-18 15:23

In Java I need to put content from an OutputStream (I fill data to that stream myself) into a ByteBuffer. How to do it in a simple way?

相关标签:
6条回答
  • 2021-02-18 15:44

    // access the protected member buf & count from the extend class

    class ByteArrayOutputStream2ByteBuffer extends ByteArrayOutputStream {
        public ByteBuffer toByteBuffer() {
            return ByteBuffer.wrap(buf, 0, count);
        }
    }
    
    0 讨论(0)
  • 2021-02-18 15:47

    There is a more efficient variant of @DJClayworth's answer.

    As @seh correctly noticed, ByteArrayOutputStream.toByteArray() returns a copy of the backing byte[] object, which may be inefficient. However, the backing byte[] object as well as the count of the bytes are both protected members of the ByteArrayOutputStream class. Hence, you can create your own variant of the ByteArrayOutputStream exposing them directly:

    public class MyByteArrayOutputStream extends ByteArrayOutputStream {
      public MyByteArrayOutputStream() {
      }
    
      public MyByteArrayOutputStream(int size) {
        super(size);
      }
    
      public int getCount() {
        return count;
      }
    
      public byte[] getBuf() {
        return buf;
      }
    }
    

    Using this class is easy:

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

    As a result, once all the output is written the same buffer is used as the basis of an input stream.

    0 讨论(0)
  • 2021-02-18 15:49

    Though the above-mention answers solve your problem, none of them are efficient as you expect from NIO. ByteArrayOutputStream or MyByteArrayOutputStream first write the data into a Java heap memory and then copy it to ByteBuffer which greatly affects the performance.

    An efficient implementation would be writing ByteBufferOutputStream class yourself. Actually It's quite easy to do. You have to just provide a write() method. See this link for ByteBufferInputStream.

    0 讨论(0)
  • 2021-02-18 15:54

    You say you're writing to this stream yourself? If so, maybe you could implement your own ByteBufferOutputStream and plug n' play.

    The base class would look like so:

    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();
        }
        /*
    }
    
    0 讨论(0)
  • 2021-02-18 16:00

    Try using PipedOutputStream instead of OutputStream. You can then connect a PipedInputStream to read the data back out of the PipedOutputStream.

    0 讨论(0)
  • 2021-02-18 16:10

    You can create a ByteArrayOutputStream and write to it, and extract the contents as a byte[] using toByteArray(). Then ByteBuffer.wrap(byte []) will create a ByteBuffer with the contents of the output byte array.

    0 讨论(0)
提交回复
热议问题