在 java.io.InputStream 及其子类型中可靠地跳过数据

2022-09-04 21:13:12

我正在处理二进制流,需要有效地跳过我不感兴趣的数据范围,到将要处理的某些数据。

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

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

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

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

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

所以我的问题是:你能以这样一种方式利用吗?你知道流何时结束或跳过何时成功完成?InputStream.skip(long)


答案 1

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

因此,我提出以下建议:

/**
 * 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?我们不能以强有力的方式做到这一点。例如,如果我们调用 FileInputStream 对象,即使我们位于 ,或者文件只有 2 个字节,它也将返回 8。但是该方法是健壮的,因为它可以做我们想要做的事情:跳过字节(如果可能的话)并让我继续处理它(如果我的下一次读取返回,我会知道已经到达)。skip(8)EOFn-1EOF


答案 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


推荐