Pergunta

Deve ser bastante simples: Eu tenho uma InputStream onde eu quero espiar (não ler) os primeiros dois bytes, ou seja, eu quero que a "posição atual" do InputStream para stil estar em 0 depois de minha espreitar. Qual é o melhor e mais segura maneira de fazer isso?

Resposta - Como eu suspeitava, a solução era envolvê-la em um BufferedInputStream que ofertas markability. Graças Rasmus.

Foi útil?

Solução

Para um InputStream geral, gostaria de envolvê-la em um BufferedInputStream e fazer algo como isto:

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

Outras dicas

Ao usar um BufferedInputStream make certeza de que o inputStream não estiver em buffer, o buffer duplo vai causar algum sério difícil encontrar bugs. Além disso, você precisa lidar com leitores de forma diferente, convertendo a um StreamReader e buffer causará bytes para ser perdido se o leitor é tamponado. Além disso, se você estiver usando um leitor lembrar que você não está lendo bytes, mas caracteres na codificação padrão (a menos que uma codificação explícita foi definido). Um exemplo de um fluxo de entrada buffer, que você pode não saber é URL url; url.openStream ();

Eu não tenho quaisquer referências para esta informação, ele vem de depuração de código. O principal caso em que o problema ocorreu por mim estava no código que lida de um arquivo em um fluxo comprimido. Se bem me lembro uma vez que você iniciar a depuração através do código há comentários na fonte Java que certas coisas não funcionam corretamente sempre. Não me lembro de onde a informação de usar BufferedReader e BufferedInputStream vem, mas eu acho que falha imediatamente no mesmo o mais simples teste. Lembre-se de testar isso, você precisa estar marcando mais do que o tamanho do buffer (que é diferente para BufferedReader contra BufferedInputStream), os problemas ocorrem quando os bytes sendo alcance de leitura no final do buffer. Nota existe um tamanho do buffer de código-fonte que pode ser diferente para o tamanho do buffer definido no construtor. É um tempo desde que eu fiz isso para minhas lembranças de detalhes pode ser um pouco fora. O teste foi feito usando uma FilterReader / FilterInputStream, adicionar um para o fluxo direto e um para o fluxo de buffer para ver a diferença.

Eu encontrei uma implementação de um PeekableInputStream aqui:

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

A idéia da implementação mostrado no artigo é que ele mantém uma matriz de valores "apareciam" internamente. Quando você liga para ler, os valores são retornados primeiro a partir da matriz espiou, em seguida, a partir do fluxo de entrada. Quando você chama espiada, os valores são lidos e armazenados na matriz "espiou".

Como a licença do código de exemplo é LGPL, Ele pode ser anexado a este post:

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top