DataInputStream.skipBytes(n)何时不能跳过n个字节?

时间:2008-09-09 08:19:02

标签: io java

Sun Documentation for DataInput.skipBytes表示它“尝试从输入流中跳过n个字节的数据,丢弃跳过的字节。但是,它可能会跳过一些较小的字节数,可能为零。来自任何一个条件的结果;在跳过n个字节之前到达文件末尾只有一种可能性。“

  1. 除了到达文件末尾之外,为什么skipBytes()不能跳过正确的字节数? (我使用的DataInputStream将包裹FileInputStreamPipedInputStream。)

  2. 如果我肯定想跳过n个字节并抛出一个EOFException,如果这导致我转到文件的末尾,我应该使用readFully()并忽略生成的字节数组吗?或者有更好的方法吗?

5 个答案:

答案 0 :(得分:5)

1)可能没有那么多数据可供读取(管道的另一端可能还没有发送那么多数据),并且实现类可能是非阻塞的(即它只会返回它可以返回的内容) ,而不是等待足够的数据来完成请求。)

但是,我不知道是否有任何实现以这种方式实现,但是接口的设计允许它。

另一种选择就是文件在读取过程中部分关闭。

2)readFully()(它总是等待足够的输入或者失败)或者在循环中调用skipBytes()。我认为前者可能更好,除非阵列真的很大。

答案 1 :(得分:2)

我今天遇到了这个问题。它正在读取虚拟机上的网络连接,所以我想可能有很多原因导致这种情况发生。我通过简单地强制输入流跳过字节直到它跳过我想要的字节数来解决它:

int byteOffsetX = someNumber; //n bytes to skip
int nSkipped = 0;

nSkipped = in.skipBytes(byteOffsetX);
while (nSkipped < byteOffsetX) {
    nSkipped = nSkipped + in.skipBytes(byteOffsetX - nSkipped);
}

答案 2 :(得分:1)

Josh Bloch最近公布了此消息。它是一致的,因为InputStream.read不能保证尽可能多地读取字节数。但是,作为API方法,它完全没有意义。 InputStream可能也应该有readFully。

答案 3 :(得分:1)

事实证明,readFully()会增加比我愿意忍受的更多性能开销。

最后我妥协了:我调用了skipBytes()一次,如果返回少于正确的字节数,我会调用readFully()来获取剩余的字节。

答案 4 :(得分:0)

根据文档,readFully()是工作和保证工作的唯一方式。

Oracle的实际实现令人困惑:

public final int skipBytes(int n) throws IOException {
    int total = 0;
    int cur = 0;

    while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) {
        total += cur;
    }

    return total;
}

skip()skipBytes()具有基本相同的约定时,为什么循环调用skip()?如果满足以下两个条件,则以这种方式实现此方法将是非常有意义的:skipBytes()确保在EOF, {{ 1}}保证尽可能跳过至少一个字节(就像skip()一样)。

更糟糕的是,read()实际上是使用skip()实现的,这意味着它实际上确实起作用。它只是没有做到这一点,这意味着其他实现可能会失败(甚至如果将来的发行版中进行更改,甚至Oracle将来也可能会失败)。

为了完全安全:请调用read(),如果它不起作用,请分配一个临时缓冲区,然后调用readBytes()(如果可以跳过任意大的数量,请在此处使用循环)数据)。

另一方面,循环调用readFully()是没有意义的。至少在Oracle实施中,因为它已经是一个循环。