2012-08-13 9 views
5

Ich habe etwas geschrieben, um einen Anfragestream (der gziped Daten enthält) von einer eingehenden HttpServletRequest ('Anfrage' unten) zu lesen, aber es scheint, dass die normale InputStream Lesemethode nicht wirklich alle Inhalte liest?InputStream.read (Byte [], 0 Länge) stoppt früh?

Mein Code war:

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

Was ich während des Tests war, dass manchmal das Oberteil (für, wenn eine Inhaltslänge vorhanden ist) würde nur aufhören teilweise durch die eingehende Anfrage Stream zu lesen und den Rest lassen des 'empfangenen' Byte-Array-Leerzeichens. Wenn ich es einfach immer den sonst Teil der if-Anweisung ausführen lassen, liest es sich gut und alle erwarteten Bytes werden in "erhalten" platziert.

So scheint es, als ob ich jetzt meinen Code mit dieser Änderung allein lassen kann, aber hat irgendjemand eine Idee warum die normale 'read' (byte [], int, int) 'Methode aufhört zu lesen? Die Beschreibung besagt, dass es anhalten kann, wenn ein Dateiende vorhanden ist. Könnte es sein, dass die gezippten Daten einfach nur Bytes enthielten, die mit der Signatur übereinstimmten?

+0

BTW, möchten Sie vielleicht einen Blick auf [GZIPInputStream] (http://docs.oracle.com/javase/7/docs/api/java/util/zip/GZIPInputStream.html). Anstatt alles in ein Byte-Array zu lesen und dann die Daten separat zu dekomprimieren, können Sie den unformatierten InputStream einfach in einen GZIPInputStream schreiben und die dekomprimierten Daten direkt lesen. –

+0

Ah, der Grund, warum wir das nicht direkt tun, ist, dass manchmal die Eingaben, die wir von anderen Systemen erhalten, nicht gezippt werden, obwohl es eigentlich sein soll ... :) –

Antwort

8

Sie müssen eine while Schleife an der Spitze hinzufügen, um alle Bytes zu erhalten. Der Strom wird versuchen, so viele Bytes wie möglich zu lesen, aber es ist nicht len Bytes erforderlich sofort zurückzukehren:

Es wird versucht, so viele wie len Bytes zu lesen, aber eine kleinere Zahl gelesen werden , möglicherweise Null.

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: fixiert, während.

+0

Ah, das funktioniert super, danke! –

+1

übrigens, Sie sollten wirklich nicht die Länge der Anfrage verwenden, um die Daten zu lesen. Die Methode read() gibt -1 zurück, wenn sie das Ende der Eingabe erreicht. Dies sollte Ihr Hinweis darauf sein, ob die Daten erschöpft sind. – Matt

1

Sie müssen sehen, wie viel des Puffers gefüllt war. Es gibt nur garantiert mindestens ein Byte.

Vielleicht was Sie wollten, war DataInputStream.readFully();

+0

Ja, ich habe Kommentare dazu auf anderen Posts gesehen über dieses Problem - es würde wahrscheinlich auch für mich arbeiten, aber während dies zu beheben schien es sinnvoller, nur die eine Art des Lesens der Ausgabe zu behalten :) Einzige Sache ist ich bin mir nicht sicher, ob dies langsamer als die eingebaute Methode sein wird ... Wir erwarten nur kurze (bis zu 20k vielleicht?) Eingehende Anfragen, also ist es wahrscheinlich egal. Die Ausgabe der "read" -Methode war korrekt in Bezug darauf, wie viel tatsächlich gelesen wurde - d. H. Für eine 11k-Byte-Eingabe würde sie angeben, dass sie nur 7k Bytes liest. Ich bin nur nicht sicher, warum es das getan hat! –

+2

Es gibt Ihnen so viele Daten zur Verfügung, so dass Sie es verarbeiten können, bevor Sie mehr lesen. Dies ist effizienter als das Warten auf alle Daten zuerst vor der Verarbeitung von esp, wenn die Daten sehr groß sind. –

Verwandte Themen