2012-08-13 14 views
5

He estado escribiendo algo para leer un flujo de solicitud (que contiene datos comprimidos) de una HttpServletRequest entrante ('solicitud' a continuación), sin embargo, parece que el método de lectura de InputStream normal no lee realmente todo el contenido?InputStream.read (byte [], 0 longitud) se detiene antes de tiempo?

Mi código era:

InputStream requestStream = request.getInputStream(); 
if ((length = request.getContentLength()) != -1) 
{ 
    received = new byte[length]; 
    requestStream.read(received, 0, length); 
} 
else 
{ 
    // create a variable length list of bytes 
    List<Byte> bytes = new ArrayList<Byte>(); 

    boolean endLoop = false; 
    while (!endLoop) 
    { 
     // try and read the next value from the stream.. if not -1, add it to the list as a byte. if 
     // it is, we've reached the end. 
     int currentByte = requestStream.read(); 
     if (currentByte != -1) 
      bytes.add((byte) currentByte); 
     else 
      endLoop = true; 
    } 
    // initialize the final byte[] to the right length and add each byte into it in the right order. 
    received = new byte[bytes.size()]; 
    for (int i = 0; i < bytes.size(); i++) 
    { 
     received[i] = bytes.get(i); 
    } 
} 

Lo que encontré durante la prueba era que a veces la parte superior (para cuando una longitud de contenido está presente) acaba de dejar de leer parte del camino a través del torrente solicitud entrante y dejar el resto del conjunto de bytes 'recibido' en blanco. Si solo hago que ejecute la parte else de la declaración if en todo momento, se lee bien y todos los bytes esperados se colocan en 'received'.

Por lo tanto, parece que ahora puedo dejar mi código solo con ese cambio, pero ¿alguien tiene alguna idea de por qué dejó de leer el método normal de "lectura" (byte [], int, int)? La descripción dice que puede detenerse si hay un final de archivo presente. ¿Podría ser que los datos gzip solo incluyan bytes que coincidan con la firma que se parezca?

+0

Por cierto, es posible que desee echar un vistazo a [GZIPInputStream] (http://docs.oracle.com/javase/7/docs/api/java/util/zip/GZIPInputStream.html). En lugar de leer todo en una matriz de bytes y luego descomprimir los datos por separado, puede envolver el InputStream sin procesar en un GZIPInputStream y leer los datos descomprimidos directamente. –

+0

Ah, la razón por la que no hacemos eso directamente es porque a veces la entrada que recibimos de otros sistemas no está realmente comprimida aunque se supone que es ... :) –

Respuesta

8

Necesita agregar un bucle while en la parte superior para obtener todos los bytes. La corriente intentará leer tantos bytes como puede, pero no está obligado a devolver len bytes a la vez:

se hace un intento de leer tantos como len bytes, pero un número menor puede leer posiblemente cero.

if ((length = request.getContentLength()) != -1) 
{ 
    received = new byte[length]; 
    int pos = 0; 
    do { 
     int read = requestStream.read(received, pos, length-pos); 

     // check for end of file or error 
     if (read == -1) { 
      break; 
     } else { 
      pos += read; 
     } 
    } while (pos < length); 
} 

EDIT: mientras fija.

+0

¡Ah, eso funciona genial, gracias! –

+1

por cierto, realmente no debería usar la longitud de solicitud para leer los datos. el método read() devolverá un -1 cuando llegue al final de la entrada. Este debería ser su indicador de si los datos están agotados. – Matt

1

Necesita ver qué parte del búfer se ha llenado. Solo se garantiza que le dará al menos un byte.

Quizás lo que quería era DataInputStream.readFully();

+0

Sí, he visto comentarios sobre eso en otras publicaciones sobre este tema, probablemente también me funcione, pero mientras lo solucionaba, me pareció más sensato mantener la única forma de leer el resultado :) Lo único es que no estoy seguro de si esto será más lento que el método incorporado. ... Sin embargo, solo esperamos solicitudes de entrada cortas (¡hasta 20 mil, quizás!), Por lo que probablemente no importe. La salida del método de "lectura" era correcta en términos de cuánto leyó en realidad, es decir, para una entrada de 11k bytes indicará que solo lee 7k bytes. ¡No estoy seguro de por qué hizo eso! –

+2

Le brinda la mayor cantidad de datos disponibles en este momento para que pueda procesarlos antes de leer un poco más. Esto es más eficiente que esperar primero todos los datos antes de procesar esp si los datos son muy grandes. –

Cuestiones relacionadas