2008-09-29 7 views
27

Sollte ziemlich einfach sein: Ich habe einen InputStream, wo ich die ersten zwei Bytes sehen (nicht lesen) möchte, d. H. Ich möchte die "aktuelle Position" des InputStream nach dem Spähen bei 0 bleiben. Was ist der beste und sicherste Weg, dies zu tun?Wie gucke ich auf die ersten zwei Bytes in einem InputStream?

Antwort - Wie ich vermutet hatte, bestand die Lösung darin, es in einen BufferedInputStream zu verpacken, der Markierbarkeit bietet. Danke Rasmus.

Antwort

47

Für eine allgemeine Input, würde ich es in einem BufferedInputStream wickeln und so etwas tun:

BufferedInputStream bis = new BufferedInputStream(inputStream); 
bis.mark(2); 
int byte1 = bis.read(); 
int byte2 = bis.read(); 
bis.reset(); 
// note: you must continue using the BufferedInputStream instead of the inputStream 
+0

Siehe auch http://java.sun.com/javase/6/docs/api/java/io/InputStream.html#markSupported () – McDowell

+0

funktioniert wie ein Charme, danke! – Epaga

4

ich eine Implementierung eines PeekableInputStream hier:

http://www.heatonresearch.com/articles/147/page2.html

Die Idee Die Implementierung, die in diesem Artikel gezeigt wird, enthält intern eine Reihe von "peeked" Werten. Wenn Sie read aufrufen, werden die Werte zuerst vom Peeked-Array und dann vom Eingabestream zurückgegeben. Wenn Sie peek aufrufen, werden die Werte gelesen und im Array "peeked" gespeichert.

Als Lizenz des Beispielcodes wird LGPL, es kann zu diesem Beitrag angehängt werden:

package com.heatonresearch.httprecipes.html; 

import java.io.*; 

/** 
* The Heaton Research Spider Copyright 2007 by Heaton 
* Research, Inc. 
* 
* HTTP Programming Recipes for Java ISBN: 0-9773206-6-9 
* http://www.heatonresearch.com/articles/series/16/ 
* 
* PeekableInputStream: This is a special input stream that 
* allows the program to peek one or more characters ahead 
* in the file. 
* 
* This class is released under the: 
* GNU Lesser General Public License (LGPL) 
* http://www.gnu.org/copyleft/lesser.html 
* 
* @author Jeff Heaton 
* @version 1.1 
*/ 
public class PeekableInputStream extends InputStream 
{ 

    /** 
    * The underlying stream. 
    */ 
    private InputStream stream; 

    /** 
    * Bytes that have been peeked at. 
    */ 
    private byte peekBytes[]; 

    /** 
    * How many bytes have been peeked at. 
    */ 
    private int peekLength; 

    /** 
    * The constructor accepts an InputStream to setup the 
    * object. 
    * 
    * @param is 
    *   The InputStream to parse. 
    */ 
    public PeekableInputStream(InputStream is) 
    { 
    this.stream = is; 
    this.peekBytes = new byte[10]; 
    this.peekLength = 0; 
    } 

    /** 
    * Peek at the next character from the stream. 
    * 
    * @return The next character. 
    * @throws IOException 
    *   If an I/O exception occurs. 
    */ 
    public int peek() throws IOException 
    { 
    return peek(0); 
    } 

    /** 
    * Peek at a specified depth. 
    * 
    * @param depth 
    *   The depth to check. 
    * @return The character peeked at. 
    * @throws IOException 
    *   If an I/O exception occurs. 
    */ 
    public int peek(int depth) throws IOException 
    { 
    // does the size of the peek buffer need to be extended? 
    if (this.peekBytes.length <= depth) 
    { 
     byte temp[] = new byte[depth + 10]; 
     for (int i = 0; i < this.peekBytes.length; i++) 
     { 
     temp[i] = this.peekBytes[i]; 
     } 
     this.peekBytes = temp; 
    } 

    // does more data need to be read? 
    if (depth >= this.peekLength) 
    { 
     int offset = this.peekLength; 
     int length = (depth - this.peekLength) + 1; 
     int lengthRead = this.stream.read(this.peekBytes, offset, length); 

     if (lengthRead == -1) 
     { 
     return -1; 
     } 

     this.peekLength = depth + 1; 
    } 

    return this.peekBytes[depth]; 
    } 

    /* 
    * Read a single byte from the stream. @throws IOException 
    * If an I/O exception occurs. @return The character that 
    * was read from the stream. 
    */ 
    @Override 
    public int read() throws IOException 
    { 
    if (this.peekLength == 0) 
    { 
     return this.stream.read(); 
    } 

    int result = this.peekBytes[0]; 
    this.peekLength--; 
    for (int i = 0; i < this.peekLength; i++) 
    { 
     this.peekBytes[i] = this.peekBytes[i + 1]; 
    } 

    return result; 
    } 

} 
5

Wenn ein BufferedInputStream sich immer vergewissern, dass die input nicht bereits gepuffert, einige doppelte Pufferung ernsthaft hart verursachen um Fehler zu finden. Auch müssen Sie Leser anders behandeln, das Konvertieren zu einem StreamReader und dem Puffern führt dazu, dass Bytes verloren gehen, wenn der Reader gepuffert ist. Auch wenn Sie einen Reader verwenden, denken Sie daran, dass Sie keine Bytes, sondern Zeichen in der Standardcodierung lesen (sofern keine explizite Codierung festgelegt wurde). Ein Beispiel für einen gepufferten Eingabestream, den Sie möglicherweise nicht kennen, ist URL URL; url.openStream();

Ich habe keine Referenzen für diese Informationen, es kommt aus dem Debugging-Code. Der Hauptfall, in dem das Problem für mich auftrat, war Code, der aus einer Datei in einen komprimierten Stream gelesen wurde. Wenn ich mich richtig erinnere, sobald Sie das Debuggen über den Code beginnen, gibt es Kommentare in der Java-Quelle, dass bestimmte Dinge nicht immer korrekt funktionieren. Ich erinnere mich nicht, woher die Informationen aus der Verwendung von BufferedReader und BufferedInputStream stammen, aber ich denke, das scheitert sofort am einfachsten Test. Denken Sie daran, dies zu testen, müssen Sie mehr als die Puffergröße markieren (was für BufferedReader versus BufferedInputStream unterscheidet), treten die Probleme auf, wenn die gelesenen Bytes das Ende des Puffers erreichen. Hinweis: Es gibt eine Puffergröße für den Quellcode, die sich von der im Konstruktor festgelegten Puffergröße unterscheiden kann. Es ist eine Weile her, dass ich dies getan habe, so dass meine Erinnerungen an Details ein wenig abweichen könnten. Das Testen wurde mit einem FilterReader/FilterInputStream durchgeführt, fügen Sie einen zum direkten Stream und einen zum gepufferten Stream hinzu, um den Unterschied zu sehen.

+1

Interessant! Haben Sie Details zu den Problemen mit Double Buffering und der Kombination von BufferedInputStream mit InputStreamReader? Ich konnte beim Googlen nichts finden. –

+0

Ich denke, die Sorge über Doppelpufferung ist fehl am Platz und in der Regel gegen die Stream-Architektur. Die Ströme sollen aufeinander gestapelt werden, ohne dass man das Innere des anderen kennt. Sofern Sie keine genauen Angaben haben, was Sie nicht tun, würde ich sagen, dass das Problem, das Sie gesehen haben, in Ihrem Code enthalten sein könnte. –