2009-09-08 12 views
12

es la siguiente:¿Cómo inicializar un ByteBuffer si no sabe cuántos bytes asignar de antemano?

ByteBuffer buf = ByteBuffer.allocate(1000); 

... la única manera de inicializar una ByteBuffer?

¿Qué pasa si no tengo idea de cuántos bytes necesito asignar ...?

Editar: Más detalles:

Me estoy convirtiendo formato de un archivo de imagen en un archivo TIFF. El problema es que el formato del archivo inicial puede ser de cualquier tamaño, pero necesito escribir los datos en el TIFF para little endian. Así que estoy leyendo las cosas que finalmente voy a imprimir en el archivo TIFF en el ByteBuffer primero, así que puedo poner todo en Little Endian, luego voy a escribirlo en el archivo. Supongo que como sé cuánto duran los IFD, los encabezados, y probablemente pueda calcular cuántos bytes en cada plano de imagen, puedo usar múltiples ByteBuffers durante todo este proceso.

Respuesta

7

Depende

Biblioteca

la conversión de formatos de archivo tiende a ser un problema resuelto por la mayoría de los dominios del problema. Por ejemplo:

  • Batik puede transcodificar entre varios formatos de imagen (incluido TIFF).
  • Apache POI puede convertir entre formatos de hoja de cálculo de oficina.
  • Flexmark puede generar HTML a partir de Markdown.

La lista es larga. La primera pregunta debería ser: "¿Qué library puede realizar esta tarea?" Si el rendimiento es una consideración, es probable que dedique mejor su tiempo optimizando un paquete existente para satisfacer sus necesidades que escribiendo otra herramienta. (Como beneficio adicional, otras personas llegar a beneficiarse del trabajo centralizado.)


cantidades conocidas

  • La lectura de un archivo? Asignar file.size() bytes.
  • ¿Copiando una cadena? Asignar string.length() bytes.
  • ¿Copiando un paquete TCP? Asigne 1500 bytes, por ejemplo.

cantidades desconocidas

Cuando es verdaderamente desconoce el número de bytes, puede hacer algunas cosas:

  • hacer una conjetura.
  • Analizar conjuntos de datos de ejemplo en el búfer; usa la longitud promedio

Ejemplo

de Java StringBuffer, a menos que se indique lo contrario, utiliza un tamaño de búfer inicial para contener 16 caracteres. Una vez que se llenan los 16 caracteres, se asigna una nueva matriz más larga y luego se copian los 16 caracteres originales. Si el StringBuffer tenía un tamaño inicial de 1024 caracteres, entonces la reasignación no ocurriría tan temprano o con tanta frecuencia.

Optimización

De cualquier manera, esto es probablemente una optimización prematura. Normalmente, debe asignar un número determinado de bytes cuando desee reducir el número de reasignaciones de memoria interna que se ejecutan.

Es poco probable que este sea el cuello de botella de la aplicación.

+3

Un' StringBuffer' se comporta de manera diferente. Un 'ByteBuffer' arrojaría una' BufferOverflowException' si intentas agregar más. – bvdb

4

La idea es que es solo un buffer - no todos los datos. Es un lugar de descanso temporal para los datos a medida que lee un trozo, lo procesa (posiblemente lo escriba en otro lugar). Por lo tanto, asigne un "pedazo" lo suficientemente grande y normalmente no será un problema.

¿Qué problema estás anticipando?

10

Los tipos de lugares que usaría un ByteBuffer son generalmente los tipos de lugares que de otra forma usaría una matriz de bytes (que también tiene un tamaño fijo). Con las E/S síncronas, a menudo se utilizan matrices de bytes, con E/S asíncrona, en su lugar se usan ByteBuffers.

Si usted necesita leer una cantidad desconocida de datos utilizando un ByteBuffer, considerar el uso de un bucle con su tampón y anexar los datos a un ByteArrayOutputStream mientras lo lee. Cuando haya terminado, llame al toByteArray() para obtener la matriz de bytes final.

En cualquier momento cuando no esté del todo seguro del tamaño (o tamaño máximo) de una entrada determinada, lea en un bucle (posiblemente usando ByteArrayOutputStream, pero simplemente procesando los datos como una secuencia, como se lee) es la única forma de manejarlo. Sin algún tipo de bucle, los datos restantes se perderán, por supuesto.

Por ejemplo:

final byte[] buf = new byte[4096]; 
int numRead; 

// Use try-with-resources to auto-close streams. 
try(
    final FileInputStream fis = new FileInputStream(...); 
    final ByteArrayOutputStream baos = new ByteArrayOutputStream() 
) { 
    while ((numRead = fis.read(buf)) > 0) { 
    baos.write(buf, 0, numRead); 
    } 

    final byte[] allBytes = baos.toByteArray(); 

    // Do something with the data. 
} 
catch(final Exception e) { 
    // Do something on failure... 
} 

Si en vez quería escribir Java int s, u otras cosas que no son bytes sin formato, se puede envolver su ByteArrayOutputStream en un DataOutputStream:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
DataOutputStream dos = new DataOutputStream(baos); 

while (thereAreMoreIntsFromSomewhere()) { 
    int someInt = getIntFromSomewhere(); 
    dos.writeInt(someInt); 
} 

byte[] allBytes = baos.toByteArray();  
+0

¿Puedes dar un ejemplo de esto usando ByteArrayOutputStream? ¿Como digamos para un número entero? –

+0

@PaulaKristin Compruébelo ahora (también he corregido el enlace 'ByteArrayOutputStream' roto) –

Cuestiones relacionadas