Java Language
ByteBuffer
Buscar..
Introducción
La clase ByteBuffer
se introdujo en Java 1.4 para facilitar el trabajo en datos binarios. Es especialmente adecuado para usar con datos de tipo primitivo. Permite la creación, pero también la manipulación posterior de un byte[]
s en un nivel de abstracción superior
Sintaxis
- byte [] arr = new byte [1000];
- ByteBuffer buffer = ByteBuffer.wrap (arr);
- ByteBuffer buffer = ByteBuffer.allocate (1024);
- ByteBuffer buffer = ByteBuffer.allocateDirect (1024);
- byte b = buffer.get ();
- byte b = buffer.get (10);
- corto s = buffer.getShort (10);
- buffer.put ((byte) 120);
- buffer.putChar ('a');
Uso básico - Creación de un ByteBuffer
Hay dos formas de crear un ByteBuffer
, donde uno puede subdividirse de nuevo.
Si ya tiene un byte[]
existente, puede "envolverlo" en un ByteBuffer
para simplificar el procesamiento:
byte[] reqBuffer = new byte[BUFFER_SIZE];
int readBytes = socketInputStream.read(reqBuffer);
final ByteBuffer reqBufferWrapper = ByteBuffer.wrap(reqBuffer);
Esta sería una posibilidad para el código que maneja las interacciones de redes de bajo nivel.
Si no tiene un byte[]
ya existente byte[]
, puede crear un ByteBuffer
sobre una matriz que está asignada específicamente para el búfer de esta manera:
final ByteBuffer respBuffer = ByteBuffer.allocate(RESPONSE_BUFFER_SIZE);
putResponseData(respBuffer);
socketOutputStream.write(respBuffer.array());
Si la ruta del código es extremadamente crítica para el rendimiento y necesita acceso directo a la memoria del sistema , ByteBuffer
puede incluso asignar búferes directos utilizando #allocateDirect()
Uso básico - Escribir datos en el búfer
Dado un ByteBuffer
ejemplo uno puede escribir datos de tipo primitivo a él utilizando relativa y absoluta put
. La sorprendente diferencia es que al poner los datos utilizando el método relativo , se realiza un seguimiento del índice en el que se insertan los datos, mientras que el método absoluto siempre requiere proporcionar un índice para put
los datos.
Ambos métodos permiten "encadenar" llamadas. Dado un búfer suficientemente dimensionado, se puede hacer lo siguiente:
buffer.putInt(0xCAFEBABE).putChar('c').putFloat(0.25).putLong(0xDEADBEEFCAFEBABE);
que es equivalente a:
buffer.putInt(0xCAFEBABE);
buffer.putChar('c');
buffer.putFloat(0.25);
buffer.putLong(0xDEADBEEFCAFEBABE);
Tenga en cuenta que el método que opera en byte
s no tiene un nombre especial. Además, tenga en cuenta que también es válido pasar tanto un ByteBuffer
como un byte[]
para put
. Aparte de eso, todos los tipos primitivos tienen métodos de put
especializados.
Una nota adicional: el índice dado cuando se usa put*
absoluto put*
siempre se cuenta en byte
.
Uso básico - Uso de DirectByteBuffer
DirectByteBuffer
es una implementación especial de ByteBuffer
que no tiene byte[]
debajo.
Podemos asignar dicho ByteBuffer llamando a:
ByteBuffer directBuffer = ByteBuffer.allocateDirect(16);
Esta operación asignará 16 bytes de memoria. El contenido de los buffers directos puede residir fuera del montón de recolección de basura normal.
Podemos verificar si ByteBuffer es directo llamando a:
directBuffer.isDirect(); // true
La principal característica de DirectByteBuffer
es que JVM intentará trabajar de forma nativa en la memoria asignada sin ningún búfer adicional, por lo que las operaciones realizadas en él pueden ser más rápidas que las realizadas en ByteBuffers con arrays ubicados debajo.
Se recomienda usar DirectByteBuffer
con operaciones de IO pesadas que dependen de la velocidad de ejecución, como la comunicación en tiempo real.
Debemos tener en cuenta que si intentamos utilizar el método array()
obtendremos la UnsupportedOperationException
. Por lo tanto, es una buena práctica comprobar si nuestro ByteBuffer lo tiene (matriz de bytes) antes de intentar acceder a él:
byte[] arrayOfBytes;
if(buffer.hasArray()) {
arrayOfBytes = buffer.array();
}
Otro uso del buffer de bytes directo es interoperar a través de JNI. Como un búfer de bytes directo no usa un byte[]
, sino un bloque de memoria real, es posible acceder a esa memoria directamente a través de un puntero en el código nativo. Esto puede ahorrarle un poco de problemas y gastos generales al calcular entre Java y la representación nativa de los datos.
La interfaz JNI define varias funciones para manejar buffers de bytes directos: Soporte NIO .