java 如何查看 InputStream 中的前两个字节?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/148130/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I peek at the first two bytes in an InputStream?
提问by Epaga
Should be pretty simple: I have an InputStream where I want to peek at (not read) the first two bytes, i.e. I want the "current position" of the InputStream to stil be at 0 after my peeking. What is the best and safest way to do this?
应该很简单:我有一个 InputStream,我想在其中查看(而不是读取)前两个字节,即我希望 InputStream 的“当前位置”在查看后仍为 0。什么是最好和最安全的方法来做到这一点?
Answer- As I had suspected, the solution was to wrap it in a BufferedInputStream which offers markability. Thanks Rasmus.
答案- 正如我所怀疑的,解决方案是将它包装在一个提供可标记性的 BufferedInputStream 中。谢谢拉斯姆斯。
回答by Rasmus Faber
For a general InputStream, I would wrap it in a BufferedInputStream and do something like this:
对于一般的 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
回答by Alex Miller
You might find PushbackInputStream to be useful:
您可能会发现 PushbackInputStream 很有用:
http://docs.oracle.com/javase/6/docs/api/java/io/PushbackInputStream.html
http://docs.oracle.com/javase/6/docs/api/java/io/PushbackInputStream.html
回答by Donal Tobin
When using a BufferedInputStream make sure that the inputStream is not already buffered, double buffering will cause some seriously hard to find bugs. Also you need to handle Readers differently, converting to a StreamReader and Buffering will cause bytes to be lost if the Reader is Buffered. Also if you are using a Reader remember that you are not reading bytes but characters in the default encoding (unless an explicit encoding was set). An example of a buffered input stream, that you may not know is URL url; url.openStream();
使用 BufferedInputStream 时,请确保 inputStream 尚未缓冲,双缓冲会导致一些严重难以发现的错误。您还需要以不同方式处理 Readers,如果 Reader 被缓冲,则转换为 StreamReader 和 Buffering 将导致字节丢失。此外,如果您使用的是 Reader,请记住您不是在读取字节而是在默认编码中读取字符(除非设置了显式编码)。您可能不知道的缓冲输入流示例是 URL url;url.openStream();
I do not have any references for this information, it comes from debugging code. The main case where the issue occurred for me was in code that read from a file into a compressed stream. If I remember correctly once you start debugging through the code there are comments in the Java source that certain things do not work correctly always. I do not remember where the information from using BufferedReader and BufferedInputStream comes from but I think that fails straight away on even the simplest test. Remember to test this you need to be marking more than the buffer size (which is different for BufferedReader versus BufferedInputStream), the problems occur when the bytes being read reach the end of the buffer. Note there is a source code buffer size which can be different to the buffer size you set in the constructor. It is a while since I did this so my recollections of details may be a little off. Testing was done using a FilterReader/FilterInputStream, add one to the direct stream and one to the buffered stream to see the difference.
我没有任何关于此信息的参考,它来自调试代码。对我来说出现问题的主要情况是在从文件读取到压缩流的代码中。如果我没记错的话,一旦您开始通过代码进行调试,Java 源代码中就会有一些注释,指出某些事情并不总是能正常工作。我不记得使用 BufferedReader 和 BufferedInputStream 的信息来自哪里,但我认为即使是最简单的测试也会立即失败。请记住要对此进行测试,您需要标记的不仅仅是缓冲区大小(BufferedReader 与 BufferedInputStream 不同),当读取的字节到达缓冲区末尾时会出现问题。请注意,源代码缓冲区大小可能与您在构造函数中设置的缓冲区大小不同。我已经有一段时间没有这样做了,所以我对细节的回忆可能有点偏差。测试是使用 FilterReader/FilterInputStream 完成的,在直接流中添加一个,在缓冲流中添加一个以查看差异。
回答by Mario Ortegón
I found an implementation of a PeekableInputStream here:
我在这里找到了 PeekableInputStream 的实现:
http://www.heatonresearch.com/articles/147/page2.html
http://www.heatonresearch.com/articles/147/page2.html
The idea of the implementation shown in the article is that it keeps an array of "peeked" values internally. When you call read, the values are returned first from the peeked array, then from the input stream. When you call peek, the values are read and stored in the "peeked" array.
文章中显示的实现的想法是它在内部保留了一个“偷看”值的数组。当您调用 read 时,值首先从 peeked 数组返回,然后从输入流中返回。当您调用 peek 时,值被读取并存储在“peeked”数组中。
As the license of the sample code is LGPL, It can be attached to this post:
由于示例代码的许可是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;
}
}

