tobytearray ioutils array java nio inputstream bytebuffer

java - ioutils.tobytearray import



Envolviendo un ByteBuffer con un InputStream (5)

Esta es mi versión de la implementación de InputStream y OutputStream :

ByteBufferBackedInputStream :

public class ByteBufferBackedInputStream extends InputStream { private ByteBuffer backendBuffer; public ByteBufferBackedInputStream(ByteBuffer backendBuffer) { Objects.requireNonNull(backendBuffer, "Given backend buffer can not be null!"); this.backendBuffer = backendBuffer; } public void close() throws IOException { this.backendBuffer = null; } private void ensureStreamAvailable() throws IOException { if (this.backendBuffer == null) { throw new IOException("read on a closed InputStream!"); } } @Override public int read() throws IOException { this.ensureStreamAvailable(); return this.backendBuffer.hasRemaining() ? this.backendBuffer.get() & 0xFF : -1; } @Override public int read(@Nonnull byte[] buffer) throws IOException { return this.read(buffer, 0, buffer.length); } @Override public int read(@Nonnull byte[] buffer, int offset, int length) throws IOException { this.ensureStreamAvailable(); Objects.requireNonNull(buffer, "Given buffer can not be null!"); if (offset >= 0 && length >= 0 && length <= buffer.length - offset) { if (length == 0) { return 0; } else { int remainingSize = Math.min(this.backendBuffer.remaining(), length); if (remainingSize == 0) { return -1; } else { this.backendBuffer.get(buffer, offset, remainingSize); return remainingSize; } } } else { throw new IndexOutOfBoundsException(); } } public long skip(long n) throws IOException { this.ensureStreamAvailable(); if (n <= 0L) { return 0L; } int length = (int) n; int remainingSize = Math.min(this.backendBuffer.remaining(), length); this.backendBuffer.position(this.backendBuffer.position() + remainingSize); return (long) length; } public int available() throws IOException { this.ensureStreamAvailable(); return this.backendBuffer.remaining(); } public synchronized void mark(int var1) { } public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); } public boolean markSupported() { return false; } }

ByteBufferBackedOutputStream :

public class ByteBufferBackedOutputStream extends OutputStream { private ByteBuffer backendBuffer; public ByteBufferBackedOutputStream(ByteBuffer backendBuffer) { Objects.requireNonNull(backendBuffer, "Given backend buffer can not be null!"); this.backendBuffer = backendBuffer; } public void close() throws IOException { this.backendBuffer = null; } private void ensureStreamAvailable() throws IOException { if (this.backendBuffer == null) { throw new IOException("write on a closed OutputStream"); } } @Override public void write(int b) throws IOException { this.ensureStreamAvailable(); backendBuffer.put((byte) b); } @Override public void write(@Nonnull byte[] bytes) throws IOException { this.write(bytes, 0, bytes.length); } @Override public void write(@Nonnull byte[] bytes, int off, int len) throws IOException { this.ensureStreamAvailable(); Objects.requireNonNull(bytes, "Given buffer can not be null!"); if ((off < 0) || (off > bytes.length) || (len < 0) || ((off + len) > bytes.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } backendBuffer.put(bytes, off, len); } }

Tengo un método que toma un InputStream y lee datos de él. Me gustaría utilizar este método con un ByteBuffer también. ¿Hay alguna manera de ajustar un ByteBuffer para que se pueda acceder como una transmisión?


No hay nada en el JDK, pero hay muchas implementaciones, google for ByteBufferInputStream. Básicamente envuelven uno o más ByteBuffers y hacen un seguimiento de un índice que registra cuánto se ha leído. Algo como esto aparece mucho, pero aparentemente tiene errores, vea la respuesta de @Mike Houston para una versión mejorada ).


Parece haber algunos errores con la implementación mencionada por Thilo, y también copiar y pegar textualmente en otros sitios:

  1. ByteBufferBackedInputStream.read() devuelve un signo int extendido representación del byte que lee, que es incorrecto (el valor debe estar en el rango [-1..255])
  2. ByteBufferBackedInputStream.read(byte[], int, int) no devuelve -1 cuando no quedan bytes en el búfer, según las especificaciones de la API

ByteBufferBackedOutputStream parece relativamente sólido.

Presento una versión ''fija'' a continuación. Si encuentro más errores (o alguien los señala) lo actualizaré aquí.

Actualizado: eliminó synchronized palabras clave synchronized de los métodos de lectura / escritura

Flujo de entrada

public class ByteBufferBackedInputStream extends InputStream { ByteBuffer buf; public ByteBufferBackedInputStream(ByteBuffer buf) { this.buf = buf; } public int read() throws IOException { if (!buf.hasRemaining()) { return -1; } return buf.get() & 0xFF; } public int read(byte[] bytes, int off, int len) throws IOException { if (!buf.hasRemaining()) { return -1; } len = Math.min(len, buf.remaining()); buf.get(bytes, off, len); return len; } }

Flujo de salida

public class ByteBufferBackedOutputStream extends OutputStream { ByteBuffer buf; public ByteBufferBackedOutputStream(ByteBuffer buf) { this.buf = buf; } public void write(int b) throws IOException { buf.put((byte) b); } public void write(byte[] bytes, int off, int len) throws IOException { buf.put(bytes, off, len); } }


Si está respaldado por una matriz de bytes, puede usar un ByteArrayInputStream y obtener la matriz de bytes a través de ByteBuffer.array() . Esto generará una excepción si lo estás probando en un ByteBuffer nativo.


Utilice el almacenamiento intermedio de almacenamiento dinámico (matriz de bytes) directamente si está disponible; de ​​lo contrario, use envoltura bytebuffer (consulte la respuesta Mike Houston)

public static InputStream asInputStream(ByteBuffer buffer) { if (buffer.hasArray()) { // use heap buffer; no array is created; only the reference is used return new ByteArrayInputStream(buffer.array()); } return new ByteBufferInputStream(buffer); }

También tenga en cuenta que el búfer envuelto puede admitir de manera eficiente las operaciones de marca / restablecer y omitir.