Get size of uncompressed gzip file while size of c

2019-07-12 18:56发布

问题:

I am using GZIPInputStream to download PDF file. I want to show the download progress of the file on a UI button. But, I am not getting the actual size of the file, what I am getting is compressed size due to which I am unable to show the correct download progress. This download progress is exceeding 100 as the actual file size is greater than the compressed size of file.

Header content of file from server: Following info I receive from server, from which I am using content-length which is giving compressed file size.

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

Here is my code. Is there any way to get original size of file?

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;  
    }
}

回答1:

You're looking at it the wrong way. You should be counting the compressed bytes that you read and calculating the progress based on those. Instead, you're counting the decompressed bytes and comparing it with the compressed file size. In answer to your question, there's no (reliable) way to determine the size of a gzipped file without decompressing it.

Update: Here's one way you could count the uncompressed bytes coming in. Wrap the raw input stream with a TeeInputStream before wrapping it with the GZIPInputStream. Make the TeeInputStream branch to a CountingOutputStream. Then you'll always have a current count of the compressed bytes that have been downloaded via getByteCount()



回答2:

This issue discuss result seems not way to avoid HttpURLConnection.getInputStream() automatically returned GZIPInputStream, once you let HttpURLConnection accept gzip compression, you won't calculate download progress accurately, the only one we can do just disable gzip as acceptable encoding :

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

Another choice is use AndroidHttpClient, I had tested about this, even we present accept gzip encoding like this :

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

the InputStream instance that return by HttpResponse.getEntity().getContent() will be EofSensorInputStream, an original InputStream is what we wanted, isn't GZIPInputStream, that make us possible to wrap it to GZIPInputStream by myself, we can use TeeInputStream and CountingOutputStream to finish calculating download progress.

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());
}

I think that's all we can do with this problem, I tried pick up android libcore source with my project so we can customize HttpURLConnectionImpl then suppress it return GZIPInputStream, but many errors makes trouble, I discard this effort.

In this post, Jesse Wilson suggested we the best choice client of Android is HttpURLConnection, so I'm looking for how to solve this problem always, I hope I can get a way soon.