InputStreamの最初の2バイトを覗くにはどうすればよいですか?
-
02-07-2019 - |
質問
かなりシンプルなはずです:最初の2バイトを(読み取らずに)覗きたいInputStreamがあります。つまり、「現在の位置」が必要です。ピーク後も入力ストリームを0のままにします。これを行うための最良かつ最も安全な方法は何ですか?
回答-私が疑っていたように、解決策はマーク可能性を提供するBufferedInputStreamにラップすることでした。ラスマスに感謝します。
解決
一般的な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
他のヒント
PushbackInputStreamが役立つと思うかもしれません:
http://docs.oracle.com/ javase / 6 / docs / api / java / io / PushbackInputStream.html
BufferedInputStreamを使用するときは、inputStreamが既にバッファリングされていないことを確認してください。ダブルバッファリングにより、バグを見つけるのが非常に困難になります。 また、リーダーを別の方法で処理する必要があります。StreamReaderに変換すると、リーダーがバッファリングされている場合、バッファリングによりバイトが失われます。 また、リーダーを使用している場合は、バイトではなくデフォルトのエンコードの文字を読み取ることに注意してください(明示的なエンコードが設定されていない場合)。 バッファリングされた入力ストリームの例としては、URL urlがあります。 url.openStream();
この情報の参照はありません。デバッグコードから取得したものです。 私にとって問題が発生した主なケースは、ファイルから圧縮ストリームに読み込むコードでした。 コードを介してデバッグを開始したときに正しく覚えていれば、Javaソースには特定のものが常に正しく動作しないというコメントがあります。 BufferedReaderとBufferedInputStreamを使用した情報がどこにあるか覚えていない から来ますが、最も単純なテストでもすぐに失敗すると思います。 これをテストすることを忘れないでください。バッファサイズ(BufferedReaderとBufferedInputStreamで異なります)よりも多くのマークを付ける必要があります。読み取り中のバイトがバッファの最後に達すると問題が発生します。 コンストラクタで設定したバッファサイズとは異なるソースコードバッファサイズがあることに注意してください。 私がこれをやったのでしばらくして、私の詳細の思い出が少しずれているかもしれません。 テストはFilterReader / FilterInputStreamを使用して行われ、1つを直接ストリームに追加し、もう1つをバッファリングされたストリームに追加して、違いを確認します。
ここでPeekableInputStreamの実装を見つけました:
http://www.heatonresearch.com/articles/147/page2.html
この記事に示されている実装の考え方は、「ピーク」の配列を保持することです。内部的に値。 readを呼び出すと、まずピーク配列から値が返され、次に入力ストリームから値が返されます。ピークを呼び出すと、値が読み取られて「ピーク」に保存されます。配列。
サンプルコードのライセンスは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;
}
}