2

我正在使用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;  
    }
}
4

2 回答 2

0

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

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

于 2013-03-05T03:16:30.147 回答
0

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

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

另一种选择是使用AndroidHttpClient,我已经对此进行了测试,即使我们现在也接受这样的 gzip 编码:

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

HttpResponse.getEntity().getContent()返回的 InputStream 实例将是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,但是很多错误都会造成麻烦,我放弃了这个努力。

在这篇文章中,Jesse Wilson 建议我们最好选择 Android 客户端是 HttpURLConnection,所以我一直在寻找如何解决这个问题,希望我能尽快找到方法。

于 2014-05-06T08:48:49.670 回答