Java InputStream读缓冲区

时间:2017-04-20 13:52:53

标签: java inputstream zipinputstream

说我试图从这样的Java InputStream中读取:

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,因为我想阅读下一个短文。我想将缓冲区设置为4,如果我想读取下一个int,依此类推其他类型。问题是,即使我知道有足够的未读数据来填充缓冲区,有时zis.read(缓冲区)也不会填充缓冲区。我可以简单地将整个文件内容转储到一个数组中并解析它,但后来我最终实现了我自己的流读取器来做那个似乎重新发明轮子的东西。我还可以实现一个read()函数来检查读取计数,如果小于buffersize,请求更多的数据来填充缓冲区,但这样做效率低且难看。有更好的方法吗?

这是对此处发布的问题的后续问题:

Java ZipInputStream extraction errors

3 个答案:

答案 0 :(得分:1)

  

有更好的方法吗?

嗯...... ZipInputStream最终继承自InputStream,因此您应该能够使用BufferedInputStream然后使用DataInputStream来包装它并使用{{读取数据1}},readShort等等。

这样的事情:

readInt

注意:您不应该关闭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确保您不会在底层流上执行大量小读取...这将是不好的。

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

答案 1 :(得分:0)

您需要检查字节数并继续阅读,直到获得所需的所有信息

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...

答案 2 :(得分:0)

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

并且有充分的理由以这种方式定义API,它使得实现可以自由地在部分数据可用时立即返回而不会在等待数据变得可用时长时间阻塞(想想SocketInputStream)

如果您需要最少量的数据,则需要重复调​​用读取,直到您已阅读所需数据以继续处理为止。

至于&#34;那是低效和丑陋的&#34;,通过批量读取方法读取少量数据会产生自己的开销,并且可能在您显示的代码中也为每个创建一个垃圾字节[]你读过的数据实体。对于读取少量字节,您可以简单地使用read()方法返回单个字节,以简单的实用方法实现,例如:

 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内的一些数组索引边界检查。它不会导致过多的调用到本机数据源。