2012-08-13 8 views
5

Ho scritto qualcosa per leggere un flusso di richiesta (contenente dati gzip) da una HttpServletRequest in arrivo ('richiesta' di seguito), tuttavia sembra che il normale metodo di lettura di InputStream non legga effettivamente tutto il contenuto?InputStream.read (byte [], lunghezza 0) si arresta in anticipo?

Il mio codice è:

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); 
    } 
} 

Quello che ho trovato durante i test è che a volte la parte superiore (per quando una lunghezza del contenuto è presente) sarebbe solo smettere di leggere in parte attraverso il flusso di richiesta in ingresso e lasciare il resto della matrice di byte 'ricevuti' vuota. Se faccio in modo che esegua sempre la parte else dell'istruzione if, legge bene e tutti i byte previsti vengono inseriti in 'received'.

Quindi, sembra che ora possa lasciare il mio codice solo con quel cambiamento, ma qualcuno ha idea del perché il normale metodo "read" (byte [], int, int) "ha smesso di leggere? La descrizione dice che potrebbe fermarsi se è presente una fine del file. Potrebbe essere che i dati gzippati capita di includere dei byte che corrispondono a qualsiasi firma?

+0

BTW, si consiglia di dare un'occhiata a [GZIPInputStream] (http://docs.oracle.com/javase/7/docs/api/java/util/zip/GZIPInputStream.html). Invece di leggere tutto in un array di byte e quindi decomprimere i dati separatamente, è sufficiente avvolgere InputStream non elaborato in un GZIPInputStream e leggere direttamente i dati decompressi. –

+0

Ah, la ragione per cui non lo facciamo direttamente è perché a volte l'input che riceviamo da altri sistemi non è effettivamente gzip anche se dovrebbe essere ... :) –

risposta

8

È necessario aggiungere un ciclo while nella parte superiore per ottenere tutti i byte. Il flusso tenterà di leggere tanti byte come può, ma non è richiesto di tornare len byte in una volta:

viene effettuato un tentativo di leggere quanti byte len, ma un numero inferiore può essere letto , possibilmente zero.

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: mentre fissa.

+0

Ah, va benissimo, grazie! –

+1

a proposito, non dovresti davvero usare la lunghezza della richiesta per leggere i dati. il metodo read() restituirà -1 quando raggiunge la fine dell'input. Questo dovrebbe essere il tuo indizio per stabilire se i dati sono esauriti. – Matt

1

È necessario verificare la quantità di buffer riempita. È garantito solo per darti almeno un byte.

Forse quello che volevi era DataInputStream.readFully();

+0

Sì, ho visto commenti a riguardo su altri post su questo problema - probabilmente funzionerebbe anche per me, ma mentre sistemavo questo sembrava più ragionevole mantenere solo l'unico modo di leggere l'output :) L'unica cosa è che non sono sicuro se questo sarà più lento del metodo integrato ... Ci aspettiamo solo richieste in arrivo brevi (fino a 20k forse?), Anche se probabilmente non importa. L'output del metodo "read" era corretto in termini di quanto effettivamente leggeva, cioè per un input da 11k byte si affermava che leggeva solo 7k byte. Non sono sicuro del perché lo abbia fatto! –

+2

Ti dà tutti i dati disponibili al momento, così puoi elaborarli prima di leggerne altri. Questo è più efficiente dell'attesa di tutti i dati prima di elaborare esp se i dati sono molto grandi. –

Problemi correlati