Pregunta

Debería ser bastante simple: tengo un InputStream donde quiero ver (no leer) los dos primeros bytes, es decir, quiero la posición actual de " " de InputStream para estar en 0 después de mi búsqueda. ¿Cuál es la mejor y más segura manera de hacer esto?

Respuesta : como sospechaba, la solución fue envolverla en un BufferedInputStream que ofrece marcabilidad. Gracias Rasmus.

¿Fue útil?

Solución

Para un InputStream general, lo envolvería en un BufferedInputStream y haría 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

Otros consejos

Cuando utilice un BufferedInputStream, asegúrese de que inputStream no esté ya almacenado en el búfer, el doble almacenamiento en búfer hará que algunos errores sean muy difíciles de encontrar. También debe manejar los Lectores de manera diferente, la conversión a un StreamReader y Buffering causará la pérdida de bytes si el Lector está Buffer. Además, si está utilizando un Reader, 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 búfer, que tal vez no conozca, es la URL url; url.openStream ();

No tengo ninguna referencia para esta información, proviene del código de depuración. El caso principal donde ocurrió el problema para mí fue en el código que se lee desde un archivo a una secuencia comprimida. Si recuerdo correctamente, una vez que empiezas a depurar a través del código, hay comentarios en la fuente de Java de que ciertas cosas no siempre funcionan correctamente. No recuerdo de dónde proviene la información del uso de BufferedReader y BufferedInputStream  viene de, pero creo que eso falla de inmediato incluso en la prueba más simple. Recuerde que para 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 configuró en el constructor. Ha pasado un tiempo desde que hice esto, por lo que mis recuerdos de los detalles pueden estar un poco fuera de lugar. La prueba se realizó utilizando un FilterReader / FilterInputStream, agregue uno a la secuencia directa y uno a la corriente con buffer para ver la diferencia.

Encontré 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 serie de "asomados" Valores internos. Cuando se llama a la lectura, los valores se devuelven primero desde la matriz que se ve y luego desde la secuencia de entrada. Cuando llama a peek, los valores se leen y se almacenan en " peeked " matriz.

Como la licencia del código de muestra es LGPL, se puede adjuntar a esta publicación:

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

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top