我有一个看似简单的问题,但我似乎无法让它正常工作。
我的“资产”文件夹中有一个 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”文件夹中,我很确定这是唯一的读取方法从此目录通过流式传输。
我有办法做到这一点吗?
感谢您的回答。我最终使用:
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,但它需要传入一个字符串,但我不确定该目录的路径是什么或如何获取它?
使用
ZipFile
API,有一个 size
方法,返回 ZipEntries
中 ZipFile
的数量。您可以从资产文件夹中读取。
示例:
int zipEntriesCount(String path) throws IOException {
ZipFile zf= new ZipFile(path);
return zf.size();
}
您的基本问题似乎是您必须在开始读取文件之前执行
progressBar.setMax()
,并且您要根据文件数量设置最大值。
您是否考虑过执行
progressBar.setMax(zin.getSize())
,然后跟踪调用 progressBar.setProgress()
时写入了多少字节,而不是读取了多少文件?这应该可以解决您的问题,并为您提供(恕我直言)更准确的进度条。
这是我基于@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();
}
用于 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()
}
}