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:
-
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]) -
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.