2008-09-29 18 views
27

Debería ser bastante simple: tengo un InputStream en el que quiero ver (no leer) los dos primeros bytes, es decir, quiero que la "posición actual" de InputStream permanezca en 0 después de mi inspección. ¿Cuál es la mejor y más segura forma de hacer esto?¿Cómo puedo ver los primeros dos bytes en un InputStream?

Respuesta - Como era de suponer, la solución fue envolverlo en un BufferedInputStream que ofrece marcabilidad. Gracias Rasmus.

Respuesta

47

Para un InputStream en general, me envuelve en un BufferedInputStream y hacer algo como esto:

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

Véase también http://java.sun.com/javase/6/docs/api/java/io/InputStream.html#markSupported () – McDowell

+0

funciona como un encanto, gracias! – Epaga

4

me encontré con una implementación de un PeekableInputStream aquí:

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

La idea de La implementación que se muestra en el artículo es que mantiene una matriz de valores "ocultos" internamente. Cuando llamas a read, los valores se devuelven primero desde la matriz peeked, luego desde la corriente de entrada. Cuando llamas a peek, los valores se leen y almacenan en la matriz "peeked".

Como la licencia del código de ejemplo se LGPL, puede ser adjuntos a este mensaje:

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

Cuando se utiliza un BufferedInputStream asegurarse de que el flujoEntrada no está amortiguada, el doble buffer hará que algunas de gravedad duro para encontrar errores. También necesita manejar los Lectores de manera diferente, convirtiendo a un StreamReader y el Buffering hará que los bytes se pierdan si el Lector está en Tampón. Además, si utiliza un lector, recuerde que no está leyendo bytes, sino caracteres en la codificación predeterminada (a menos que se haya establecido una codificación explícita). Un ejemplo de un flujo de entrada en el búfer, que puede que no sepa que es URL url; url.openStream();

No tengo ninguna referencia para esta información, proviene del código de depuración. El caso principal en el que se produjo el problema fue el código que se lee de un archivo en una secuencia comprimida. Si recuerdo correctamente una vez que comience a depurar el código, hay comentarios en la fuente Java de que ciertas cosas no funcionan siempre correctamente. No recuerdo de dónde proviene la información del uso de BufferedReader y BufferedInputStream , pero creo que falla inmediatamente incluso en la prueba más simple. Recuerde probar esto, necesita marcar más que el tamaño del búfer (que es diferente para BufferedReader versus BufferedInputStream), los problemas ocurren cuando los bytes que se leen llegan al final del búfer. Tenga en cuenta que hay un tamaño de búfer de código fuente que puede ser diferente al tamaño de búfer que estableció en el constructor. Ha pasado un tiempo desde que hice esto, por lo que mis recuerdos de detalles pueden estar un poco fuera de lugar. Las pruebas se realizaron utilizando un FilterReader/FilterInputStream, agregamos uno a la transmisión directa y otro al flujo almacenado para ver la diferencia.

+1

¡Interesante! ¿Tiene algún detalle sobre los problemas con el doble almacenamiento en búfer y con la combinación de BufferedInputStream con InputStreamReader? No pude encontrar nada buscando en Google. –

+0

Creo que la preocupación sobre el doble almacenamiento en memoria está fuera de lugar, y en general, en contra de la arquitectura de flujo. Se supone que las secuencias se apilan una encima de la otra, sin que uno sepa las partes internas de la otra. A menos que tengas datos específicos, que no conoces, diría que el problema que viste podría haber estado en tu código. –

Cuestiones relacionadas