2012-12-27 21 views
8

我正在处理一个二进制流,并且需要有效地跳过我不感兴趣的一系列数据,以处理一些将要处理的数据。从此输入流过健壮地跳过java.io.InputStream及其子类型中的数据

跳过并丢弃n个字节的数据:

InputStream.skip(long)不担保方式多大。由于各种原因,跳过方法可能会跳过一些较小的字节数,可能为0.这可能是由于许多条件中的任何一种导致的;在跳过n个字节之前达到文件结尾只是一种可能性。返回跳过的实际字节数。

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

  1. 流结束
  2. 的字节被跳过

够简单。但是,本说明书中的宽宏意味着,例如,BufferedInputStream只能跳过几个字节并返回。当然,它告诉我,它只是跳过这几个,但不知道为什么。

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

回答

8

我不认为我们可以得到一个真正的稳健实施,因为skip()方法合同是相当奇怪的。首先,EOF的行为没有很好的定义。如果我想跳过8个字节并且is.skip(8)返回0,决定是否应该再次尝试并不是微不足道的,如果某些实现在EOF时选择返回0,则存在无限循环的危险。 available()也不被信任。

因此,我提出以下建议:

/** 
* Skips n bytes. 
*/ 
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对象调用skip(8),即使我们在EOF处,或者文件只有2个字节,也要调用it will return 8。但是这种方法是强健的,因为它可以实现我们想要的功能:跳过n字节(如果可能)并让我继续处理它(如果我的下一次读取返回-1,我将知道已达到EOF)。

+0

您的回答具体说明了我一直在关注的内容。我发布了_seems_在实践中工作的代码,但我不确定它适用于'InputStream'的所有​​实现。您的扩展程序看起来很有趣,我会尽快在[我需要它的班级]试用它(https://code.google.com/p/metadata-extractor/source/browse/Source/com/drew/lang/ StreamReader.java)。目前我的API会尝试报告跳过是否成功,因此如果无法保证,我可能需要修改客户端代码。非常感谢。 –

+0

您可以修复'FileInputStream.skip()'问题:对'n-1'字节使用'while'循环;然后,在循环之后,调用'in.read()'一次。如果它返回'-1',跳过命中EOF,否则跳过成功。另外,不要忘记在顶部检查'n == 0'。 –

+0

@KannanGoundan有趣的建议。当然,缺点是至少需要两次读数(一次是“skip”加上一次“read”),这在某些情况下可能会影响性能。 – leonbloy

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所有实现正常工作。我想知道是否要实施我自己的缓冲跳跃方法。

+0

我看不出有什么'InputStream'实现可以脱离合约,说他们会返回多少字节真的被跳过。 – EJP

+0

@EJP,我同意。我很关心是否由于某种IO伪像(缓冲等)或因为流结束而跳过较少的字节。如果数据流还没有结束,'skip'仍然可以返回零。在什么时候你知道跳过不工作,因为没有更多的字节,也许它正在等待网络上的字节? –

+2

我看到的问题是我们不能确定我们不应该在'跳过== 0'时重试。此外,布尔型“skippedEnough”不被信任。看到我的答案。 – leonbloy