0

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.

WizzKidd
  • 196
  • 8

1 Answers1

0

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", ex);
        }
        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);
    }
kris larson
  • 30,387
  • 5
  • 62
  • 74
  • Thank you @kris not only have you provided an answer, you have gone further and implemented the answer into my existing code. Now if that's not spoon feeding, I don't know what is. Much appreciated! – WizzKidd Nov 18 '16 at 15:13
  • When it's copy/pasting a bunch of code and changing a handful of lines, I'm happy to do that. :) – kris larson Nov 18 '16 at 15:33