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

发布于 2024-11-25 17:25:55 字数 928 浏览 1 评论 0原文

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

我的“assets”文件夹中有一个 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”中' 文件夹我很确定从该目录读取的唯一方法是通过流式传输。

我有办法实现这个目标吗?

I have a question that seems easy but I cannot seem to get it to work properly.

I have a zip file within my 'assets' folder that I need to unzip and I have a ProgessBar in which I want to display to the user how the progress is going.

I have everything working but I want to set the ProgessBar max value to be the number of files within the zip file. The number of files within this folder will sometimes change so I want the ProgessBar to be relative to how many files are contained within the zip.

I'm using the ZipInputStream-API but does not seem there is a way to get the number of files within the zip file. The only way I can of think of is doing this:

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

This works but having two while loops seems a bit redundant which are basically doing the same thing.

I know that there is a ZipFile-API which has a size()-method, but it requires a path to the file and since my file is located within the 'assets' folder I am pretty sure the only way to read from this directory is by streaming.

Is there a way for me to accomplish this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

回忆凄美了谁 2024-12-02 17:25:55

感谢您的回答。我最终使用: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,但它需要传入一个字符串,但我不确定该目录的路径是什么或如何获取它?

Thanks for the answers. What I ended up doing using the: AssetFileDescriptor API to get the file size of the zip file and setting that as the ProgessBar.setMax() value. Then as I loop through the zip contents I increment the progress by using each entries file size. This works but the only concern I have is that the AssetFileDescriptor.getLength() value as well as the ZipEntry.getSize() values return a long value so I am forced to cast them to an integer before I can set the max and/or increment the ProgessBar so there is a slight possibility I might overload an integer value causing an exception but this is not likely because I do not anticipate my file sizes ever getting bigger than the max holding capacity of an integer.

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

Not the best solution but it works.

I'm aware of the ZipFile API but it requires a string to be passed in but I am not sure what the path is to that directory or how to get it?

夏雨凉 2024-12-02 17:25:55

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

例子:

int zipEntriesCount(String path) throws IOException {

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

Use ZipFile API, There is a size method that returns the number of ZipEntries in the ZipFile. You can read from assets folder.

example:

int zipEntriesCount(String path) throws IOException {

     ZipFile zf= new ZipFile(path);
     return zf.size();
}
蓬勃野心 2024-12-02 17:25:55

您的基本问题似乎是您必须在开始读取文件之前执行 progressBar.setMax() ,并且您要根据文件数量设置最大值。

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

Your basic problem seems to be that you have to do progressBar.setMax() before you start reading the file, and you are setting the max based on the number of files.

Have you thought about doing progressBar.setMax(zin.getSize()) and then keeping track of how many bytes you've written when you call progressBar.setProgress(), instead of how many files you've read? This should solve your problem and will give you (imho) a more accurate progress bar.

破晓 2024-12-02 17:25:55

这是我基于@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();
}

this is my solution based on @davorb idea which is to show progress based on file size and not content of zip file.

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

}

Example of using it :

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();
}
过期情话 2024-12-02 17:25:55

对于 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()
    }
}

for 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()
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文