WizzKidd WizzKidd - 21 days ago 7
Android Question

Set ProgressBar maxValue and publishProgress values during GZIP decompressing

I have a an AsyncTask that is performing the job of decompressing a GZIP file. I've only just learnt that I can publish the progress of AsyncTasks, and have successfully managed to get this working with other AsyncTasks that I have previously created. I understand that in order to do this, 2 important values are required, the maximum value and the current progress value.

The problem I have is that I am unsure how to retrieve these values from the input stream. My current AsyncTask looks like this:

package com.wizzkidd.myapp.asynctasks;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;

public class DecompressGzipAsync extends AsyncTask<String, Integer, Boolean> {

ProgressBar progressBar;
private Context _context;
private View _view;
private String _compressedFilePath;
private String _uncompressedFilePath;

public DecompressGzipAsync(Context context, View view, String compressedFilePath) {
this._context = context;
this._view = view;
this._compressedFilePath = compressedFilePath;
this._uncompressedFilePath = compressedFilePath.substring(0, compressedFilePath.lastIndexOf(".")); //path + filename without gz extension
}

@Override
protected void onPreExecute() {
super.onPreExecute();
}

@Override
protected Boolean doInBackground(String... strings) {
Boolean isSuccess = false;
byte[] buffer = new byte[1024];
try {
GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(_compressedFilePath));
FileOutputStream out = new FileOutputStream(_uncompressedFilePath);
//FIXME: I think I need the file size here?
//progressBar.setMax(???);
int len;
while ((len = gzis.read(buffer)) > 0) {
out.write(buffer, 0, len);
//FIXME: I'm not sure what incrementing value can I put in here?
//publishProgress(???);
}
gzis.close();
out.close();
isSuccess = true;
} catch (IOException ex) {
ex.printStackTrace();
}
return isSuccess;
}

@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int currentValue = values[0];
int maxValue = progressBar.getMax();
Log.v("TAG", "Decompressing Progress... currentValue: " + currentValue + " | maxValue: " + maxValue);
}

@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
Log.v("TAG", "Decompressing - Completed");
} else {
Log.v("TAG", "Decompressing - Failed");
}
}
}


I've commented in my code where I believe I need to find the values, but need some help here. Any help is appreciated.

Answer

According to this post, the last four bytes of the file contain the uncompressed file size (which implies a limit of 4GB).

So this should work:

    @Override
    protected Boolean doInBackground(String... strings) {
        Boolean isSuccess = false;
        byte[] buffer = new byte[1024];
        try {
            RandomAccessFile raf = new RandomAccessFile(new File(_compressedFilePath), "r");
            raf.seek(raf.length() - 4);
            int b4 = raf.read();
            int b3 = raf.read();
            int b2 = raf.read();
            int b1 = raf.read();
            int uncompressedSize = ((0xFF & b1) << 24) | ((0xFF & b2) << 16) |
                    ((0xFF & b3) << 8) | (0xFF & b4);
            raf.close();

            GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(_compressedFilePath));
            FileOutputStream out = new FileOutputStream(_uncompressedFilePath);
            int count = 0;
            int len;
            while ((len = gzis.read(buffer)) > 0) {
                out.write(buffer, 0, len);
                count += len;
                publishProgress(count, uncompressedSize);
            }
            gzis.close();
            out.close();
            isSuccess = true;
        } catch (IOException ex) {
            Log.e("DecompressGzipAsync", "error unzipping file", e);
        }
        return isSuccess;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        int count = values[0];
        int uncompressedSize = values[1];
        int maxValue = progressBar.getMax();
        int progress = (int) ((float) count / (float) uncompressedSize * maxValue);
        if (progress > maxValue) progress = maxValue;  // sanity check
        progressBar.setProgress(progress);
        Log.v("DecompressGzipAsync", "Decompressing Progress... currentValue: " + progress + " | maxValue: " + maxValue);
    }