2008-09-29 21 views
27

应该很简单:我有一个InputStream,我希望偷看(不读取)前两个字节,即我希望InputStream的“当前位置”在我窥视后仍为0。什么是最好和最安全的方法来做到这一点?如何查看InputStream中的前两个字节?

答案 - 正如我所怀疑的,解决方案是将其包装在提供可标记性的BufferedInputStream中。谢谢Rasmus。

回答

47

对于一般的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 
+0

参见http://java.sun.com/javase/6/docs/api/java/io/InputStream.html#markSupported( ) – McDowell 2008-09-29 10:13:40

+0

作品像魅力,谢谢! – Epaga 2008-09-29 10:31:34

4

我发现了一个PeekableInputStream这里的实现:

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

的想法文章中显示的实现是它在内部保留一组“窥视”值。当你调用read时,首先从peeked数组返回值,然后从输入流返回值。当你调用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; 
    } 

} 
5

当使用的BufferedInputStream确保InputStream的尚未缓冲,双缓冲会导致一些严重的硬找到错误。 此外,您需要以不同的方式处理读者,转换为StreamReader并且缓冲器会导致字节在读者缓冲时丢失。 另外,如果您使用的是Reader,请记住您不是读取字节,而是使用默认编码中的字符(除非设置了明确的编码)。 一个缓冲输入流的例子,你可能不知道的是URL url; url.openStream();

我没有任何关于此信息的参考,它来自调试代码。 问题发生在我身上的主要情况是在从文件读入压缩流的代码中。 如果我没有记错,一旦你开始通过代码进行调试,那么在Java源代码中有一些评论说某些事情总是无法正常工作。 我不记得使用BufferedReader和BufferedInputStream 的信息来自哪里,但我认为即使是最简单的测试也会失败。 记住要测试这个,你需要标记的不止是缓冲区的大小(BufferedReader与BufferedInputStream的不同),当读取的字节到达缓冲区的末尾时会出现问题。 请注意,源代码缓冲区大小可能与您在构造函数中设置的缓冲区大小不同。 这是一段时间,因为我这样做,所以我对细节的回忆可能有点关闭。 使用FilterReader/FilterInputStream完成测试,将一个添加到直接流,一个添加到缓冲流以查看差异。

+1

有趣!你有没有关于双缓冲和BufferedInputStream与InputStreamReader相结合的问题的任何细节? Google找不到任何内容。 – 2008-09-29 10:44:35