首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java InputStream读取缓冲器

Java InputStream读取缓冲器
EN

Stack Overflow用户
提问于 2017-04-20 13:52:53
回答 3查看 3.4K关注 0票数 1

假设我试图从这样的Java InputStream中读到:

代码语言:javascript
运行
复制
ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\temp\\sample3.zip"));
zis.getNextEntry();
byte[] buffer2 = new byte[2];
int count = zis.read(buffer2));
if(count != -1) //process...
else...//something wrong, abort

我正在解析一个二进制文件,在本例中,我将缓冲区设置为2,因为我想读下一个简短的内容。如果我想读取其他类型的下一个int等等,我会将缓冲区设置为4大小。问题是,即使我知道有足够的未读数据来填充缓冲区,有时zis.read(缓冲区)也不会填充缓冲区。我可以简单地将整个文件内容转储到一个数组中并对其进行解析,但最后我实现了自己的流读取器,这样做似乎是重新发明了轮子。我还可以实现一个read()函数,该函数检查读取计数,如果小于缓冲区大小,则请求更多数据来填充缓冲区,但这是低效和丑陋的。有更好的方法吗?

以下是以下问题的后续问题:

Java ZipInputStream extraction errors

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-04-20 14:51:51

有更好的方法吗?

好吧..。ZipInputStream最终继承自InputStream,因此您应该能够用BufferedInputStreamDataInputStream包装它,并使用readShortreadInt等来读取数据。

就像这样:

代码语言:javascript
运行
复制
while (zis.getNextEntry() != null) {
  DataInputStream dis = new DataInputStream(new BufferedInputStream(zis));
  boolean done = false;
  do {
    short s = dis.readShort();
    int i = dis.readInt();
    ...
  } while (!done);
}

注意:您不应该关闭dis流,因为这会导致zis关闭。(显然,zis需要在外部级别关闭,以避免资源泄漏。)

堆栈中的BufferedInputStream确保您不会在底层流上执行大量的小读取.那就太糟了。

唯一可能的问题是,它的方法对二进制数据的表示方式有特殊的想法;例如,数字是双元的。如果这是一个问题,请考虑将整个zip条目读入一个字节数组,并将其包装在一个ByteBuffer中。

票数 1
EN

Stack Overflow用户

发布于 2017-04-20 14:08:02

您需要检查字节计数并继续读取,直到得到所需的所有信息为止。

代码语言:javascript
运行
复制
zis.getNextEntry();
byte[] buffer2 = new byte[2];
int count = 0;
while (count < 2) {
  int bytesRead = zis.read(buffer2, count, 2 - count));
  if(bytesRead != -1) {
    count += bytesRead;
  }
  else...//something wrong, abort
}
//process...
票数 0
EN

Stack Overflow用户

发布于 2017-04-20 14:32:55

ZipInputStream符合InputStream定义的契约。阅读(byte[].)方法允许并记录为流结束时返回-1,或者返回(1...requested长度)之间的任何值。

而且有很好的理由用这种方式定义API,它使实现可以在不阻塞很长一段时间的情况下返回部分数据,同时等待数据变得可用(想想SocketInputStream)。

如果需要最少数量的数据,则需要反复调用read,直到读取足够多的数据才能继续处理。

至于“低效和丑陋”,通过大容量读取方法读取少量数据会产生自己的开销,并且可能在代码中还显示为您读取的每个数据实体创建一个垃圾byte[]。对于读取少量字节,您可以使用read()方法返回单个字节,该方法在一个简单的实用方法中实现,例如:

代码语言:javascript
运行
复制
 static short readShort(InputStream in) throws IOException {
      short s = 0;
      for (int i=0; i<2; ++i) {
          int read = in.read();
          if (read < 0)
              throw new IOException("unexpected end of stream");
          s = (short) ((s << 8) | read);
      }
      return s;
 }

(这可以很容易地适应其他原语类型)

单字节I/O在大多数情况下是完全可以接受的,只要您注意确保InputStream被包装到BufferedInputStream中。然后,平均开销减少到BufferedInputStream内部的几个数组索引边界检查。它不会导致对本机数据源的过多调用。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43521536

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档