Domanda

Dovrebbe essere piuttosto semplice: ho un InputStream in cui voglio sbirciare (non leggere) i primi due byte, cioè voglio la "posizione corrente". di InputStream per essere a 0 dopo la mia sbirciatina. Qual è il modo migliore e più sicuro per farlo?

Risposta - Come avevo sospettato, la soluzione era quella di avvolgerlo in un BufferedInputStream che offre marcabilità. Grazie Rasmus.

È stato utile?

Soluzione

Per un InputStream generale, lo avvolgo in un BufferedInputStream e farei qualcosa del genere:

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

Altri suggerimenti

Quando si utilizza BufferedInputStream, assicurarsi che inputStream non sia già bufferizzato, il doppio buffering renderà alcuni bug davvero difficili da trovare. Inoltre è necessario gestire i lettori in modo diverso, la conversione in StreamReader e il buffering causeranno la perdita di byte se il Reader è bufferizzato. Inoltre, se stai utilizzando un Reader, ricorda che non stai leggendo byte ma caratteri nella codifica predefinita (a meno che non sia stata impostata una codifica esplicita). Un esempio di un flusso di input bufferizzato che potresti non conoscere è l'URL dell'URL; url.openStream ();

Non ho riferimenti per queste informazioni, viene dal codice di debug. Il caso principale in cui si è verificato il problema per me è stato nel codice letto da un file in un flusso compresso. Se ricordo correttamente una volta che inizi a eseguire il debug attraverso il codice, ci sono commenti nella fonte Java che certe cose non funzionano sempre correttamente. Non ricordo dove le informazioni dall'uso di BufferedReader e BufferedInputStream  viene da ma penso che fallisca subito anche nel test più semplice. Ricordarsi di provare questo è necessario contrassegnare più della dimensione del buffer (che è diversa per BufferedReader rispetto a BufferedInputStream), i problemi si verificano quando i byte letti raggiungono la fine del buffer. Si noti che esiste una dimensione del buffer del codice sorgente che può essere diversa dalla dimensione del buffer impostata nel costruttore. È da un po 'che non lo faccio, quindi i miei ricordi di dettagli potrebbero essere un po' fuori. Il test è stato eseguito utilizzando FilterReader / FilterInputStream, aggiungerne uno allo stream diretto e uno allo stream buffer per vedere la differenza.

Ho trovato un'implementazione di un PeekableInputStream qui:

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

L'idea dell'implementazione mostrata nell'articolo è che mantiene una matrice di "sbirciata" valori internamente. Quando si chiama read, i valori vengono restituiti prima dall'array visualizzato, quindi dal flusso di input. Quando chiami sbirciatina, i valori vengono letti e memorizzati nella "quotata" " matrice.

Poiché la licenza del codice di esempio è LGPL, può essere allegata a questo 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;
  }

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top