GZIPInputStream:从解压缩文件中读取前n个字节

时间:2014-08-07 09:33:57

标签: java optimization gzip inputstream

我有一组数千个GZIP文件,我正在通过HTTP访问。每个文件的大小可能高达几百MB。我需要从这些压缩文件中的文件中读取前几个千字节(标题)。

这是我目前的做法:

URL url = new URL("http://example.com/file123.gz");
DataInputStream ds = new DataInputStream(new GZIPInputStream(url.openStream()));
byte[] header = new byte[5760];
ds.readFully(header);

我需要做的是从这个GZIP文件中的文件下载第一个5760字节,但我不希望Java下载整个文件(通常超过几MB)。

我的问题是 - Java首先下载整个GZIP文件然后解压缩,还是只下载必要数量的数据来填充byte[5760]缓冲区?如何查找从HTTP服务器实际下载的数据量?

3 个答案:

答案 0 :(得分:2)

  

Java首先下载整个GZIP文件然后解压缩,还是只下载必要数量的数据来填充字节[5760]缓冲区?

更接近后者。 Java不会首先读取整个文件。相反,url.openStream()为您提供了一个“套接字流”,可直接从套接字读取数据。

内核端套接字数据结构中可能会缓存一些数据,GZIPInputStream中可能会有更多数据缓冲。但这绝对是一个有限的数额。因此,服务器可能会发送比应用程序实际消耗的数据更多的数据,但它不太可能发送整个(兆字节大小)文件。

  

如何查找从HTTP服务器实际下载的数据量?

难以衡量,甚至难以定义。根据上下文,您似乎真的对服务器发送的数量感兴趣。衡量这一点的唯一可行方法是在服务器端,即使这很困难。 (如果你不真的需要来找到它,我建议你不要去尝试...)

答案 1 :(得分:0)

您无法指定实际下载的数据量。

为您的请求提供服务的网络服务器将打开请求的文件,并通过tcp连接发送整个内容(以http响应标头开头)。

这意味着整个文件将发送给您,除了在恰当的时间关闭底层连接之外,您无法做任何事情,但这不容易做到,特别是不能可靠地工作。这意味着:你从输入流中读取5760个字节(此时,它已经包含超过5760个字节!)然后关闭流和连接 - 但这并不意味着在此期间收到了更多的数据

要了解实际接收的数量,您必须完整阅读输入流并检查其长度。

答案 2 :(得分:0)

如果Web服务器支持字节范围请求,那么您可以告诉它只下载第一个(比如说)10kB的压缩数据(以确保在解压缩时获得至少5760个字节)

URL url = new URL("http://example.com/file123.gz");
URLConnection connection = url.openConnection();
connection.setRequestProperty("Range", "bytes=0-9999");
DataInputStream ds = new DataInputStream(
                         new GZIPInputStream(connection.getInputStream()));
byte[] header = new byte[5760];
ds.readFully(header);

您可能需要捕获此过程中抛出的任何异常,并在没有范围标题的情况下重试(尽管服务器不理解它应该只发送整个文件)。