33

非常に単純なはずです: 最初の 2 バイトを覗き見したい (読み取らない) InputStream があります。これを行うための最善かつ最も安全な方法は何ですか?

回答- 私が推測したように、解決策は、マーク可能性を提供する BufferedInputStream でラップすることでした。ありがとうラスムス。

4

4 に答える 4

53

一般的な InputStream の場合、BufferedInputStream でラップして、次のようにします。

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
于 2008-09-29T09:51:05.900 に答える
25

PushbackInputStream が役立つ場合があります。

http://docs.oracle.com/javase/6/docs/api/java/io/PushbackInputStream.html

于 2008-09-29T15:40:44.313 に答える
5

BufferedInputStreamを使用する場合は、inputStreamがまだバッファリングされていないことを確認してください。ダブルバッファリングを行うと、バグを見つけるのが非常に困難になります。また、リーダーを別の方法で処理する必要があります。StreamReaderとバッファリングに変換すると、リーダーがバッファリングされている場合にバイトが失われます。また、リーダーを使用している場合は、デフォルトのエンコーディングでバイトではなく文字を読み取っていることを忘れないでください(明示的なエンコーディングが設定されていない場合)。バッファリングされた入力ストリームの例は、あなたが知らないかもしれませんが、URLurlです。url.openStream();

私はこの情報への参照を持っていません、それはデバッグコードから来ています。私にとって問題が発生した主なケースは、ファイルから圧縮ストリームに読み込まれるコードでした。コードを介してデバッグを開始したときに正しく覚えている場合、Javaソースには、特定のものが常に正しく機能するとは限らないというコメントがあります。BufferedReaderとBufferedInputStreamを使用した情報がどこから来たのかは覚えていませんが、最も単純なテストでもすぐに失敗すると思います。これをテストすることを忘れないでください。バッファサイズ(BufferedReaderとBufferedInputStreamでは異なります)よりも多くマークする必要があります。読み取られるバイトがバッファの最後に到達すると、問題が発生します。コンストラクターで設定したバッファーサイズとは異なる可能性のあるソースコードのバッファーサイズがあることに注意してください。これを行ってからしばらく経ちますので、細部の記憶が少しずれているかもしれません。テストはFilterReader/FilterInputStreamを使用して行われ、1つを直接ストリームに追加し、もう1つをバッファリングされたストリームに追加して違いを確認します。

于 2008-09-29T10:18:50.467 に答える
4

ここで PeekableInputStream の実装を見つけました。

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

この記事に示されている実装の考え方は、「ピーク」値の配列を内部的に保持するというものです。read を呼び出すと、値は最初にピーク配列から返され、次に入力ストリームから返されます。peek を呼び出すと、値が読み取られて「peeked」配列に格納されます。

サンプル コードのライセンスは LGPL であるため、この投稿に添付できます。

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

}
于 2008-09-29T09:51:31.733 に答える