获取未压缩的gzip文件的大小,同时从服务器获得压缩文件的大小

时间:2013-03-05 03:09:01

标签: java android gzip

我正在使用GZIPInputStream下载PDF文件。我想在UI按钮上显示文件的下载进度。但是,我没有得到文件的实际大小,我得到的是压缩大小,因为我无法显示正确的下载进度。此下载进度超过100,因为实际文件大小大于压缩文件大小。

来自服务器的文件的头文件内容:我从服务器收到的以下信息,我正在使用content-length来提供压缩文件大小。

1.Connection
2.Content-Encoding
3.Content-length
4.Content-Type
5.Keep-Alive
6.Server
7.Date

这是我的代码。有没有办法获得文件的原始大小?

long fileLength =  httpResponse.getEntity().getContentLength();//
GZIPInputStream input = new GZIPInputStream(new BufferedInputStream(
        httpResponse.getEntity().getContent()));
FileOutputStream output = new FileOutputStream(destinationFilePath);

byte data[] = new byte[1024];
long total = 0;
float percentage = 0;
int count;
currentDownloadingPercentage=0;
while ((count = input.read(data)) != -1) {
    total += count;
    output.write(data, 0, count);

    // publishing the progress....
    percentage = (float)total/(float)fileLength;
    percentage *= 100;
    if ((int)percentage > (int)currentDownloadingPercentage) {
        currentDownloadingPercentage = percentage;
        Bundle resultData = new Bundle();
        resultData.putBoolean(DOWNLOAD_FAILED, false);
        resultData.putInt(DOWNLOAD_PROGRESS ,(int)percentage);
        receiver.send(processID, resultData);
        resultData = null;  
    }
}

2 个答案:

答案 0 :(得分:0)

你正在以错误的方式看待它。您应该计算您读取的压缩字节数并根据这些字节计算进度。相反,您计算解压缩的字节并将其与压缩文件大小进行比较。在回答你的问题时,没有(可靠的)方法来确定压缩文件的大小而不解压缩。

更新:以下是计算未压缩字节数的一种方法。在使用GZIPInputStream包装原始输入流之前,用原始输入流包裹TeeInputStream。将TeeInputStream分支设为CountingOutputStream。然后,您将始终拥有通过getByteCount()

下载的压缩字节的当前计数

答案 1 :(得分:0)

这个issue讨论结果似乎无法避免HttpURLConnection.getInputStream()自动返回GZIPInputStream,一旦你让HttpURLConnection接受gzip压缩,你就不会准确地计算下载进度,我们唯一能做的就是只需将gzip禁用为可接受的编码:

HttpURLConnection.setRequestProperty("Accept-Encoding", "identity");

另一种选择是使用AndroidHttpClient,我已经对此进行了测试,即使我们提供接受gzip编码,如下所示:

HttpUriRequest.addHeader("Accept-Encoding", "gzip");

HttpResponse.getEntity()返回的InputStream实例.getContent()将是 EofSensorInputStream ,原始的InputStream是我们想要的,不是GZIPInputStream ,这使我们可以自己将它包装到GZIPInputStream,我们可以使用TeeInputStream和CountingOutputStream来完成下载进度的计算。

HttpResponse response = ...;
HttpEntity entity = response.getEntity();
long fileSize = entity.getContentLength();

InputStream ins = entity.getContent(); // instance of EofSensorInputStream
CountingOutputStream coStrem = new CountingOutputStream(new ByteArrayOutputStream(100));
GZIPInputStream inStrem = new GZIPInputStream(new TeeInputStream(ins, coStrem, true));

byte[] buffer = new byte[6 * 1024]; // 6K buffer
int offset;

while ((offset = inStrem.read(buffer)) != -1) {
    tmpFileRaf.write(buffer, 0, offset);
    postDownloadProgress(fileSize, coStrem.getByteCount());
}

我认为我们可以解决这个问题,我尝试用我的项目选择android libcore来源,这样我们就可以自定义 HttpURLConnectionImpl 然后禁止它返回GZIPInputStream,但是许多错误都会造成麻烦,我放弃了这一努力。

在这个post中,Jesse Wilson建议我们Android的最佳选择是HttpURLConnection,所以我一直在寻找如何解决这个问题,我希望我能尽快找到答案。