应该很简单:我有一个InputStream,我想要查看(不读取)前两个字节,即我想要“当前位置”。在我偷看之后,我把InputStream设置为0。最好和最安全的方法是什么?

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

有帮助吗?

解决方案

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

其他提示

当使用BufferedInputStream时,确保inputStream尚未缓冲,双缓冲将导致一些人很难找到错误。 此外,您需要以不同方式处理读者,转换为StreamReader,如果Reader是缓冲的,缓冲将导致字节丢失。 此外,如果您使用的是Reader,请记住您没有读取字节,而是使用默认编码中的字符(除非设置了显式编码)。 您可能不知道的缓冲输入流的示例是URL URL; url.openStream();

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

我在这里找到了一个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;
  }

}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top