Java:输入流标记限制

时间:2012-09-05 20:37:42

标签: java inputstream

根据Java documentation,类InputStream服务器中mark方法的 readlimit 参数用于set “在标记位置变为可读之前的最大字节数限制无效“。。 我有一个名为 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 个答案:

答案 0 :(得分:5)

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

BufferedInputStream的非参数文档是“查看InputStream标记方法的常规合同”,这对我来说表明BufferedInputStream的行为不同,尽管参数文档也是如此。

InputStream指定的一般合同是

  

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

换句话说,readlimit是一个建议;流可以免于承诺和过度交付。

答案 1 :(得分:2)

如果你看一下source,特别是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),因此在您的示例中不会触发失效。

答案 2 :(得分:1)

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

  

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

     

此值始终在-1pos的范围内。如果输入流中没有标记位置,则此字段为-1。如果输入流中存在标记位置,则buf[markpos]是在reset操作之后作为输入提供的第一个字节。如果markpos不是-1,则位置buf[markpos]buf[pos-1]的所有字节都必须保留在缓冲区数组中(尽管它们可能会移动到缓冲区数组中的另一个位置,适当调整countposmarkpos)的值;除非posmarkpos之间的差异超过marklimit,否则不得丢弃它们。

希望这会有所帮助。查看课程中readreset和私有方法fill的定义,看看它们是如何结合在一起的。

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

答案 3 :(得分: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());
}