java - Crecimiento de ByteBuffer
(9)
¿Alguien ha visto alguna vez una implementación de java.nio.ByteBuffer que crecerá dinámicamente si una llamada putX () sobrepasa la capacidad?
La razón por la que quiero hacerlo de esta manera es doble:
- No sé cuánto espacio necesito antes de tiempo.
- Preferiría no hacer un nuevo ByteBuffer.allocate () luego un bulk put () cada vez que me quede sin espacio.
De hecho, los búferes autoextensibles son mucho más intuitivos para trabajar. Si puedes permitirte el lujo de la reasignación, ¿¡por qué no!
El ByteBuf
de Netty ByteBuf
da exactamente esto. Es como si hubieran tomado ByteBuffer
java.nio
y java.nio
los bordes, lo que hace que sea mucho más fácil de usar.
Además, está en Maven en un paquete de netty-buffer
independiente netty-buffer
por lo que no es necesario que incluyas el conjunto completo de Netty para usar.
Eche un vistazo a Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html que es un reemplazo de gota (envuelve el ByteBuffer)
Sin embargo, le sugiero que asigne más de lo que necesita y no se preocupe demasiado por ello. Si asigna un búfer (especialmente un búfer directo), el sistema operativo le otorga memoria virtual, pero solo utiliza memoria física cuando se usa realmente. La memoria virtual debe ser muy barata.
Otra opción es usar memoria directa con un gran buffer. Esto consume memoria virtual, pero solo usa tanta memoria física como la que usa (por página que generalmente es 4K)
Por lo tanto, si asigna un almacenamiento intermedio de 1 MB, consume 1 MB de memoria virtual, pero el único sistema operativo proporciona páginas físicas a la aplicación que realmente usa.
El efecto es que ve su aplicación usando mucha memoria virtual pero una cantidad relativamente pequeña de memoria residente.
Para serializar algo, necesitará un objeto en la entrada. Lo que puede hacer es colocar su objeto en la colección de objetos, y luego hacer bucle para obtener el iterador y ponerlos en la matriz de bytes. Luego, llame a ByteBuffer.allocate(byte[].length)
. Eso es lo que hice y funcionó para mí.
Sugiero usar un flujo de entrada para recibir datos de un archivo (con un hilo de sperate si no necesita bloqueo) y luego leer bytes en un ByteArrayOutstream que le da la capacidad de obtenerlo como una matriz de bytes. Aquí hay un ejemplo simple sin agregar demasiadas soluciones.
try (InputStream inputStream = Files.newInputStream(
Paths.get("filepath"), StandardOpenOption.READ)){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int byteRead = 0;
while(byteRead != -1){
byteRead = inputStream.read();
baos.write(byteRead);
}
ByteBuffer byteBuffer = ByteBuffer.allocate(baos.size())
byteBuffer.put(baos.toByteArray());
//. . . . use the buffer however you want
}catch(InvalidPathException pathException){
System.out.println("Path exception: " + pathException);
}
catch (IOException exception){
System.out.println("I/O exception: " + exception);
}
También puede valer la pena echarle un vistazo al DynamicChannelBuffer de Netty. Las cosas que encuentro útiles son:
-
slice(int index, int length)
- operaciones sin firmar
- índices de escritor y lector separados
Un ByteBuffer realmente no puede funcionar de esta manera, ya que su concepto de diseño es ser solo una vista de un conjunto específico, al que también puede tener una referencia directa. No podría tratar de cambiar esa matriz por una matriz más grande sin que suceda lo extraño.
Lo que quiere usar es un DataOutput
. La forma más conveniente es utilizar la biblioteca de guayaba (previa a la publicación):
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();
Pero también puedes crear un DataOutputStream a partir de un ByteArrayOutputStream de forma manual, y solo lidiar con las IOExceptions falsas al encadenarlas a AssertionErrors.
Un Vector permite un crecimiento continuo
Vector<Byte> bFOO = new Vector<Byte>();
bFOO.add ((byte) 0x00); `
Para que la E / S asíncrona funcione, debe tener memoria continua. En C puede intentar volver a asignar una matriz, pero en Java debe asignar nueva memoria. Puede escribir en ByteArrayOutputStream
y luego convertirlo a ByteBuffer
en el momento en que esté listo para enviarlo. La desventaja es que está copiando memoria, y una de las claves para una E / S eficiente es reducir el número de veces que se copia la memoria.