Android:获取 Zip 中的文件数量?

问题描述 投票:0回答:5

我有一个看似简单的问题,但我似乎无法让它正常工作。

我的“资产”文件夹中有一个 zip 文件,我需要解压缩,并且我有一个

ProgessBar
,我想在其中向用户显示进度如何。

我一切正常,但我想将

ProgessBar
最大值设置为 zip 文件中的文件数。此文件夹中的文件数量有时会发生变化,因此我希望
ProgessBar
与 zip 中包含的文件数量相关。

我正在使用

ZipInputStream
-API,但似乎没有办法获取 zip 文件中的文件数量。我能想到的唯一方法就是这样做:

   ZipInputStream zin = new ZipInputStream(getAssets().open(
                                "myFile.zip"));
   int numFiles = 0;
   int increment = 0;
   while (zin.getNextEntry() != null) {
     numFiles++;
    }

    ZipEntry ze = null;
    //Set the Max..value here..
    progessBar.setMax(numFiles);                
    while ((ze = zin.getNextEntry()) != null) {
       increment++;
       progessBar.setProgress(increment);
    }

这可行,但有两个 while 循环似乎有点多余,它们基本上做同样的事情。

我知道有一个

ZipFile
-API 具有
size()
-方法,但它需要文件的路径,并且由于我的文件位于“assets”文件夹中,我很确定这是唯一的读取方法从此目录通过流式传输。

我有办法做到这一点吗?

java android zip android-assets
5个回答
9
投票

感谢您的回答。我最终使用:

AssetFileDescriptor
API 来获取 zip 文件的文件大小并将其设置为
ProgessBar.setMax()
值。然后,当我循环遍历 zip 内容时,我通过使用每个条目的文件大小来增加进度。这是有效的,但我唯一担心的是
AssetFileDescriptor.getLength()
值以及
ZipEntry.getSize()
值返回
long
值,因此我被迫将它们转换为整数,然后才能设置最大值和/或增加
ProgessBar
因此,我有可能会重载整数值,从而导致异常,但这不太可能,因为我预计我的文件大小不会大于整数的最大容纳容量。

ZipInputStream zin = new ZipInputStream(getAssets().open(
                            "myFile.zip"));
ZipEntry ze = null;
AssetFileDescriptor mydisc = getAssets().openFd("myFile.zip");
//Size of the zip package
long size = mydisc.getLength();
long increment = 0;
dialog.setMax((int) size);
while ((ze = zin.getNextEntry()) != null) {
     increment += (int) ze.getSize();
     progessBar.setProgess((int)increment);
     //do more stuff..
}

不是最好的解决方案,但它有效。

我知道

ZipFile
API,但它需要传入一个字符串,但我不确定该目录的路径是什么或如何获取它?


6
投票

使用

ZipFile
API,有一个
size
方法,返回
ZipEntries
ZipFile
的数量。您可以从资产文件夹中读取。

示例:

int zipEntriesCount(String path) throws IOException {

     ZipFile zf= new ZipFile(path);
     return zf.size();
}

4
投票

您的基本问题似乎是您必须在开始读取文件之前执行

progressBar.setMax()
,并且您要根据文件数量设置最大值。

您是否考虑过执行

progressBar.setMax(zin.getSize())
,然后跟踪调用
progressBar.setProgress()
时写入了多少字节,而不是读取了多少文件?这应该可以解决您的问题,并为您提供(恕我直言)更准确的进度条。


1
投票

这是我基于@davorb想法的解决方案,即根据文件大小而不是zip文件的内容显示进度。

import android.content.Context;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipUtility {
    private final String TAG = "Decompress";
    private ZipExtractionCallback zipExtractionCallback;

    public ZipUtility(ZipExtractionCallback zipExtractionCallback) {
        this.zipExtractionCallback = zipExtractionCallback;
    }
//
//    private void unzipFromAssets(Context context, String zipFile, String destination) {
//        try {
//            if (destination == null || destination.length() == 0)
//                destination = context.getFilesDir().getAbsolutePath();
//            new File(destination).delete();
//            InputStream stream = context.getAssets().open(zipFile);
//            unzip(stream, destination);
////            SharedPreferenceHelper.Write(context,
////                    SharedPreferenceConst.SharedPreferenceName,
////                    SharedPreferenceConst.MapExtracted,
////                    "1");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

    private boolean deleteDirectory(String file) /*throws IOException, InterruptedException */ {

        try {
            if (new File(file).exists()) {
                String deleteCommand = "rm -rf " + file/*.getAbsolutePath()*/;
                Runtime runtime = Runtime.getRuntime();
                Process process = runtime.exec(deleteCommand);
                process.waitFor();
                return true;
            }
        } catch (Exception ignore) {
        }

        return false;
    }

    public void unzipFromPath(Context context, String zipFilePath, String destination) {

        try {
            if (destination == null || destination.length() == 0)
                destination = context.getFilesDir().getAbsolutePath();
            zipExtractionCallback.progress(0, "حذف فایل های قدیمی...");
            deleteDirectory(destination + "html");
            unzip(zipFilePath, destination);
            zipExtractionCallback.progress(0, "حذف فایل اضافی...");
            deleteDirectory(zipFilePath);
        } catch (IOException e) {
            zipExtractionCallback.error("خطا هنگام عملیات استخراج : " + e.getMessage());
            e.printStackTrace();
        }
        zipExtractionCallback.finish();
    }
//
//    public static void unzip(String zipFile, String location) {
//        try {
//            FileInputStream fin = new FileInputStream(zipFile);
//            unzip(fin, location);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
//
//    }

    private void unzip(String zipFilePath, String destination) throws IOException {
        long size = new File(zipFilePath).length();
        long decompressedSize = 0;
        InputStream stream = new FileInputStream(new File(zipFilePath));
        dirChecker(destination, "");
//        int entries = 0;
        int total = 0;
        ZipInputStream zin = new ZipInputStream(stream);

//        while ((zin.getNextEntry()) != null) {
//            if (entries % 100 == 0)
//                zipExtractionCallback.progress(0, "در حال خواندن محتویات:" + entries + " فایل");
//            entries++;
//        }
        zin.close();
        stream = new FileInputStream(new File(zipFilePath));
        int p = 0;
        long totalBytes = 0;
        int BUFFER_SIZE = 1024 * 10;
        byte[] buffer = new byte[BUFFER_SIZE];
        try {
            zin = new ZipInputStream(stream);
            ZipEntry ze = null;
            while ((ze = zin.getNextEntry()) != null) {
                decompressedSize += ze.getSize();
                //Log.v(TAG, "Unzipping " + ze.getName());
                if (ze.isDirectory()) {
                    dirChecker(destination, ze.getName());
                } else {
                    File f = new File(destination, ze.getName());
                    if (!f.exists()) {
                        boolean success = f.createNewFile();
                        if (!success) {
                            //Log.w(TAG, "Failed to create file " + f.getName());
                            continue;
                        }
                        FileOutputStream fout = new FileOutputStream(f);
                        //BufferedOutputStream out = new BufferedOutputStream(fout);
                        int count;
                        while ((count = zin.read(buffer)) != -1) {
                            fout.write(buffer, 0, count);
                            //out.write(buffer, 0, count);
                            totalBytes += count;
                        }
                        zin.closeEntry();
                        fout.close();
                    }
                }
//                int progress = 1 + (total++ * 100 / entries);
                if (size < decompressedSize)
                    size = decompressedSize;
                int progress = (int) ( (totalBytes * 100L / size));
                if (p < progress)
                    zipExtractionCallback.progress(progress, "در حال استخراج از حالت فشرده:");
                p = progress;
            }
            zin.close();
        } catch (Exception e) {
            zipExtractionCallback.error("خطا هنگام عملیات استخراج : " + e.getMessage());
            Log.e(TAG, "unzip", e);
        }
    }

    private void dirChecker(String destination, String dir) {
        File f = new File(destination, dir);

        if (!f.isDirectory()) {
            boolean success = f.mkdirs();
            if (!success) {
                Log.w(TAG, "Failed to create folder " + f.getName());
            }
        }
    }


    public interface ZipExtractionCallback {

        void progress(int progress, String status);

        void finish();

        void error(String error);
    }

}

使用示例:

private void ExtractMap(String zipFilePath,Context context) {

    new Thread(new Runnable() {
        @Override
        public void run() {

            ZipUtility zipUtility = new ZipUtility(new ZipUtility.ZipExtractionCallback() {
                @Override
                public void progress(int progress, String status) {
                    ((UpdateActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                             //todo handle ui
                        }
                    });
                }

                @Override
                public void finish() {

                    ((UpdateActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //todo handle ui
                        }
                    });

                }

                @Override
                public void error(String error) {
                    ((UpdateActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                           //todo handle ui
                        }
                    });
                }
            });

            zipUtility.unzipFromPath(context,
                    zipFilePath,
                    context.getFilesDir().getAbsolutePath() + File.separator);


        }
    }).start();
}

0
投票

用于 lingala.zip4j Zip4j

val fileDescriptorPath = fileDescriptor(zipUri)
val zipFile = ZipFile(fileDescriptorPath, password)
zipFile.use {
    zipSize =  it.fileHeaders.size
}
fileDescriptorPath?.delete()

private fun fileDescriptor(uri: Uri?): File? {
    if (uri == null) return null
    var input: FileInputStream? = null
    var output: FileOutputStream? = null
    val filePath: String = File(context.cacheDir, "tmp.zip").absolutePath
   return try {
       val parcelFileDescriptor: ParcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, "r")!!
       val fileDescriptor = parcelFileDescriptor.fileDescriptor
        input = FileInputStream(fileDescriptor)
        output = FileOutputStream(filePath)
        var read: Int
        val bytes = ByteArray(1024)
        while (input.read(bytes).also { read = it } != -1) {
            output.write(bytes, 0, read)
        }
        parcelFileDescriptor.close()
        File(filePath)
    } catch (ignored: IOException) {
        Log.v("pathFileDescriptor", "IOException: ${ignored.message}")
       null
    } finally {
        input?.close()
        output?.close()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.