8

根据Java 文档,Class InputStream 服务器中mark 方法的readlimit参数用于设置“在标记位置失效之前可以读取的最大字节数限制”。. 我有一个名为sample.txt的文件,其内容是“hello”。我写了这段代码:

import java.io.*;
public class InputStream{
 public static void main (String[] args) throws IOException {
  InputStream reader = new FileInputStream("sample.txt");
  BufferedInputStream bis = new BufferedInputStream(reader);
  bis.mark(1);
  bis.read();
  bis.read();
  bis.read();
  bis.read();
  bis.reset();
  System.out.println((char)bis.read());
 }
}

输出为“h”。但是,如果我在标记方法之后读取了多个字节,我不应该得到无效重置方法调用的错误吗?

4

4 回答 4

5

我会将其归结为文档错误。

非参数文档BufferedInputStream是“请参阅 InputStream 的标记方法的一般合同”,这对我来说表明它的BufferedInputStream行为没有不同,尽管有参数文档。

由 指定的总合同InputStream

readlimit 参数告诉此输入流允许在标记位置无效之前读取许多字节 [...] 如果从流中读取的字节数超过 readlimit 字节,则流根本不需要记住任何数据

换句话说,readlimit是一个建议;流可以自由地承诺不足和过度交付。

于 2012-09-05T21:04:01.777 回答
3

如果您查看源代码,尤其是 fill() 方法,您会看到(过了一会儿!)它只会在绝对必要时才使标记无效,即它比文档可能建议的更宽容。

...
else if (pos >= buffer.length)  /* no room left in buffer */
   if (markpos > 0) {  /* can throw away early part of the buffer */
     int sz = pos - markpos;
     System.arraycopy(buffer, markpos, buffer, 0, sz);
     pos = sz;
     markpos = 0;
   } else if (buffer.length >= marklimit) {
     markpos = -1;   /* buffer got too big, invalidate mark */
     pos = 0;        /* drop buffer contents */
     ....

默认缓冲区大小相对较大(8K),因此在您的示例中不会触发失效。

于 2012-09-05T20:58:09.873 回答
1

查看 的实现BufferedInputStream,它描述了 JavaDocs(受保护markpos字段)中标记位置的重要性:

[markpos是]调用最后一个方法pos时字段的值。mark

该值始终在 范围-1pos。如果输入流中没有标记位置,则该字段为-1。如果输入流中有标记的位置,则在操作buf[markpos]之后作为输入提供的第一个字节reset。如果markpos不是-1,则从位置buf[markpos]到的所有字节都buf[pos-1]必须保留在缓冲区数组中(尽管可以将它们移动到缓冲区数组中的另一个位置,并对 、 和 的值进行适当count调整posmarkpospos除非和直到和之间的差异markpos超过,否则它们可能不会被丢弃marklimit

希望这可以帮助。看一下 的定义readreset以及类中的私有方法fill,看看它们是如何联系在一起的。

简而言之,只有当类检索到更多数据以填充其缓冲区时,才会考虑标记位置。mark如果读取的字节数多于允许的调用,它将正确无效。因此,调用read不一定会触发公共 JavaDoc 注释中公布的行为。

于 2012-09-05T20:45:34.150 回答
1

这看起来像一个微妙的错误。如果你减少缓冲区大小,你会得到一个IOException

public static void main(String[] args) throws IOException {
    InputStream reader = new ByteArrayInputStream(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
    BufferedInputStream bis = new BufferedInputStream(reader, 3);
    bis.mark(1);
    bis.read();
    bis.read();
    bis.read();
    bis.read();
    bis.reset();
    System.out.println((char)bis.read());
}
于 2012-09-05T20:57:34.777 回答