我正在使用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;
}
}
答案 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,所以我一直在寻找如何解决这个问题,我希望我能尽快找到答案。