13

我正在处理一个二进制流,需要有效地跳过一系列我不感兴趣的数据,然后转到一些将要处理的数据。

InputStream.skip(long)在保证方面没有多大作用:

跳过并丢弃此输入流中的 n 字节数据。由于各种原因,skip 方法最终可能会跳过一些较小的字节数,可能是 0。这可能是由许多条件中的任何一个引起的;在跳过 n 个字节之前到达文件末尾只是一种可能性。返回实际跳过的字节数。

我需要知道发生了两件事之一:

  1. 直播结束
  2. 字节被跳过

很简单。但是,此描述中提供的宽大处理意味着,例如,BufferedInputStream可以跳过几个字节并返回。当然,它告诉我它只是跳过了那几个,但不清楚为什么。

所以我的问题是:您能否以InputStream.skip(long)您知道流何时结束或跳过成功完成的方式使用?

4

3 回答 3

12

我不认为我们可以得到一个真正健壮的实现,因为skip()方法契约相当奇怪。一方面,at 的行为EOF没有很好的定义。如果我想跳过 8 个字节并is.skip(8)返回0,那么决定是否应该再试一次并不是一件容易的事,如果某些实现选择返回,则存在无限循环的0危险EOF。而且available()也不值得信任。

因此,我提出以下建议:

/**
 * Skips n bytes. Best effort.
 */
public static void myskip(InputStream is, long n) throws IOException {
    while(n > 0) {
        long n1 = is.skip(n);
        if( n1 > 0 ) {
            n -= n1;
        } else if( n1 == 0 ) { // should we retry? lets read one byte
            if( is.read() == -1)  // EOF
                break;
            else 
                n--;
        } else // negative? this should never happen but...
        throw new IOException("skip() returned a negative value. This should never happen");
    }
}

我们不应该返回一个值来告知“真正跳过”的字节数吗?还是一个布尔值来通知 EOF 已达到?我们不能以稳健的方式做到这一点。例如,如果我们调用skip(8)一个FileInputStream对象,即使我们在 at ,或者文件只有 2 个字节,它也会返回 8 。EOF但是从某种意义上说,该方法是健壮的,因为它可以执行我们想要的操作:跳过n字节(如果可能)并让我继续处理它(如果我的下一次读取返回-1,我会知道EOF已经达到)。

于 2013-01-18T14:26:37.150 回答
2

这似乎适用于跳过n字节:

long skippedTotal = 0;
while (skippedTotal != n) {
    long skipped = _stream.skip(n - skippedTotal);
    assert(skipped >= 0);
    skippedTotal += skipped;
    if (skipped == 0)
        break;
}
boolean skippedEnough = skippedTotal == n;

但是,尚不清楚它是否适用于InputStream可以传递给我的库的所有实现。我想知道是否实现我自己的缓冲跳过方法是要走的路。

于 2012-12-27T16:21:25.863 回答
-1

我对这个问题迟到了 6 年。

原则上,skip(int n) 和 readFully(int n) 之间没有区别。在跳过的情况下,您对字节不感兴趣。

对于直播,即。tcp 套接字或附加到的文件,skip(n) 可能会阻塞(等待)一旦它«跳过»0 个字节,具体取决于用户的等待偏好。

返回 EOF 或 -1 表示流结束,应该将其返回给最终用户,因为在那之后不会发生任何其他事情。

为了有效地跳过文件中的字节,我会探索随机 io、通道。但是这种优化不能在任何输入流中通用。

于 2018-09-19T01:02:40.953 回答