如何在Android中以编程方式解压缩文件?
我需要一个小的代码片段,它从给定的.zip文件中解压几个文件,并根据它们在压缩文件中的格式给出单独的文件。 请张贴你的知识,帮助我。
有peno的版本优化了一下。 性能的提高是显而易见的。
private boolean unpackZip(String path, String zipname) { InputStream is; ZipInputStream zis; try { String filename; is = new FileInputStream(path + zipname); zis = new ZipInputStream(new BufferedInputStream(is)); ZipEntry ze; byte[] buffer = new byte[1024]; int count; while ((ze = zis.getNextEntry()) != null) { // zapis do souboru filename = ze.getName(); // Need to create directories if not exists, or // it will generate an Exception... if (ze.isDirectory()) { File fmd = new File(path + filename); fmd.mkdirs(); continue; } FileOutputStream fout = new FileOutputStream(path + filename); // cteni zipu a zapis while ((count = zis.read(buffer)) != -1) { fout.write(buffer, 0, count); } fout.close(); zis.closeEntry(); } zis.close(); } catch(IOException e) { e.printStackTrace(); return false; } return true; }
基于Vasily Sochinsky的回答,稍微修改了一下,
public static void unzip(File zipFile, File targetDirectory) throws IOException { ZipInputStream zis = new ZipInputStream( new BufferedInputStream(new FileInputStream(zipFile))); try { ZipEntry ze; int count; byte[] buffer = new byte[8192]; while ((ze = zis.getNextEntry()) != null) { File file = new File(targetDirectory, ze.getName()); File dir = ze.isDirectory() ? file : file.getParentFile(); if (!dir.isDirectory() && !dir.mkdirs()) throw new FileNotFoundException("Failed to ensure directory: " + dir.getAbsolutePath()); if (ze.isDirectory()) continue; FileOutputStream fout = new FileOutputStream(file); try { while ((count = zis.read(buffer)) != -1) fout.write(buffer, 0, count); } finally { fout.close(); } /* if time should be restored as well long time = ze.getTime(); if (time > 0) file.setLastModified(time); */ } } finally { zis.close(); } }
显着的差异
-
public static
– 这是一个静态的实用工具,可以在任何地方。 - 2
File
参数,因为String
是:/用于文件,而且无法指定之前要提取zip文件的位置。 还path + filename
连接> https://stackoverflow.com/a/412495/995891 -
throws
– 因为赶不上 – 添加一个尝试抓住,如果真的不感兴趣的话。 - 实际上确保在所有情况下都存在所需的目录。 不是每个zip都包含文件条目之前的所有必需的目录条目。 这有两个潜在的错误:
- 如果zip包含一个空目录,而不是生成的目录,则存在一个现有的文件,这被忽略。
mkdirs()
的返回值很重要。 - 可能会崩溃在不包含目录的zip文件。
- 如果zip包含一个空目录,而不是生成的目录,则存在一个现有的文件,这被忽略。
- 增加了写入缓冲区大小,这应该会提高性能。 存储空间通常是4k块,写入较小的块通常比需要的慢。
-
finally
使用魔法来防止资源泄漏。
所以
unzip(new File("/sdcard/pictures.zip"), new File("/sdcard"));
应该做相当于原来的
unpackZip("/sdcard/", "pictures.zip")
这是我使用的解压缩方法:
private boolean unpackZip(String path, String zipname) { InputStream is; ZipInputStream zis; try { is = new FileInputStream(path + zipname); zis = new ZipInputStream(new BufferedInputStream(is)); ZipEntry ze; while((ze = zis.getNextEntry()) != null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int count; String filename = ze.getName(); FileOutputStream fout = new FileOutputStream(path + filename); // reading and writing while((count = zis.read(buffer)) != -1) { baos.write(buffer, 0, count); byte[] bytes = baos.toByteArray(); fout.write(bytes); baos.reset(); } fout.close(); zis.closeEntry(); } zis.close(); } catch(IOException e) { e.printStackTrace(); return false; } return true; }
Android有内置的Java API。 查看java.util.zip包。
类ZipInputStream是你应该看看。 从ZipInputStream中读取ZipEntry并将其转储到文件系统/文件夹中。 检查类似的例子压缩成zip文件。
虽然已经在这里的答案效果很好,但我发现它们比我所希望的稍慢。 相反,我使用zip4j ,我认为这是最好的解决scheme,因为它的速度。 它也允许不同的压缩量的选项,我觉得这很有用。
更新2016年使用下面的类
package com.example.zip; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import android.util.Log; public class DecompressFast { private String _zipFile; private String _location; public DecompressFast(String zipFile, String location) { _zipFile = zipFile; _location = location; _dirChecker(""); } public void unzip() { try { FileInputStream fin = new FileInputStream(_zipFile); ZipInputStream zin = new ZipInputStream(fin); ZipEntry ze = null; while ((ze = zin.getNextEntry()) != null) { Log.v("Decompress", "Unzipping " + ze.getName()); if(ze.isDirectory()) { _dirChecker(ze.getName()); } else { FileOutputStream fout = new FileOutputStream(_location + ze.getName()); BufferedOutputStream bufout = new BufferedOutputStream(fout); byte[] buffer = new byte[1024]; int read = 0; while ((read = zin.read(buffer)) != -1) { bufout.write(buffer, 0, read); } bufout.close(); zin.closeEntry(); fout.close(); } } zin.close(); Log.d("Unzip", "Unzipping complete. path : " +_location ); } catch(Exception e) { Log.e("Decompress", "unzip", e); Log.d("Unzip", "Unzipping failed"); } } private void _dirChecker(String dir) { File f = new File(_location + dir); if(!f.isDirectory()) { f.mkdirs(); } } }
如何使用
String zipFile = Environment.getExternalStorageDirectory() + "/the_raven.zip"; //your zip file location String unzipLocation = Environment.getExternalStorageDirectory() + "/unzippedtestNew/"; // destination folder location DecompressFast df= new DecompressFast(zipFile, unzipLocation); df.unzip();
权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
根据@zapl的回答,解压缩进度报告:
public interface UnzipFile_Progress { void Progress(int percent, String FileName); } // unzip(new File("/sdcard/pictures.zip"), new File("/sdcard")); public static void UnzipFile(File zipFile, File targetDirectory, UnzipFile_Progress progress) throws IOException, FileNotFoundException { long total_len = zipFile.length(); long total_installed_len = 0; ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile))); try { ZipEntry ze; int count; byte[] buffer = new byte[1024]; while ((ze = zis.getNextEntry()) != null) { if (progress != null) { total_installed_len += ze.getCompressedSize(); String file_name = ze.getName(); int percent = (int)(total_installed_len * 100 / total_len); progress.Progress(percent, file_name); } File file = new File(targetDirectory, ze.getName()); File dir = ze.isDirectory() ? file : file.getParentFile(); if (!dir.isDirectory() && !dir.mkdirs()) throw new FileNotFoundException("Failed to ensure directory: " + dir.getAbsolutePath()); if (ze.isDirectory()) continue; FileOutputStream fout = new FileOutputStream(file); try { while ((count = zis.read(buffer)) != -1) fout.write(buffer, 0, count); } finally { fout.close(); } // if time should be restored as well long time = ze.getTime(); if (time > 0) file.setLastModified(time); } } finally { zis.close(); } }
public class MainActivity extends Activity { private String LOG_TAG = MainActivity.class.getSimpleName(); private File zipFile; private File destination; private TextView status; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); status = (TextView) findViewById(R.id.main_status); status.setGravity(Gravity.CENTER); if ( initialize() ) { zipFile = new File(destination, "BlueBoxnew.zip"); try { Unzipper.unzip(zipFile, destination); status.setText("Extracted to \n"+destination.getAbsolutePath()); } catch (ZipException e) { Log.e(LOG_TAG, e.getMessage()); } catch (IOException e) { Log.e(LOG_TAG, e.getMessage()); } } else { status.setText("Unable to initialize sd card."); } } public boolean initialize() { boolean result = false; File sdCard = new File(Environment.getExternalStorageDirectory()+"/zip/"); //File sdCard = Environment.getExternalStorageDirectory(); if ( sdCard != null ) { destination = sdCard; if ( !destination.exists() ) { if ( destination.mkdir() ) { result = true; } } else { result = true; } } return result; } }
– >助手类(Unzipper.java)
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipInputStream; import android.util.Log; public class Unzipper { private static String LOG_TAG = Unzipper.class.getSimpleName(); public static void unzip(final File file, final File destination) throws ZipException, IOException { new Thread() { public void run() { long START_TIME = System.currentTimeMillis(); long FINISH_TIME = 0; long ELAPSED_TIME = 0; try { ZipInputStream zin = new ZipInputStream(new FileInputStream(file)); String workingDir = destination.getAbsolutePath()+"/"; byte buffer[] = new byte[4096]; int bytesRead; ZipEntry entry = null; while ((entry = zin.getNextEntry()) != null) { if (entry.isDirectory()) { File dir = new File(workingDir, entry.getName()); if (!dir.exists()) { dir.mkdir(); } Log.i(LOG_TAG, "[DIR] "+entry.getName()); } else { FileOutputStream fos = new FileOutputStream(workingDir + entry.getName()); while ((bytesRead = zin.read(buffer)) != -1) { fos.write(buffer, 0, bytesRead); } fos.close(); Log.i(LOG_TAG, "[FILE] "+entry.getName()); } } zin.close(); FINISH_TIME = System.currentTimeMillis(); ELAPSED_TIME = FINISH_TIME - START_TIME; Log.i(LOG_TAG, "COMPLETED in "+(ELAPSED_TIME/1000)+" seconds."); } catch (Exception e) { Log.e(LOG_TAG, "FAILED"); } }; }.start(); } }
– > xml布局(activity_main.xml):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <TextView android:id="@+id/main_status" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world" /> </RelativeLayout>
– >在Menifest文件中的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
这里是一个ZipFileIterator(像一个Java Iterator,但对于zip文件):
package ch.epfl.bbp.io; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Iterator; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class ZipFileIterator implements Iterator<File> { private byte[] buffer = new byte[1024]; private FileInputStream is; private ZipInputStream zis; private ZipEntry ze; public ZipFileIterator(File file) throws FileNotFoundException { is = new FileInputStream(file); zis = new ZipInputStream(new BufferedInputStream(is)); } @Override public boolean hasNext() { try { return (ze = zis.getNextEntry()) != null; } catch (IOException e) { e.printStackTrace(); } return false; } @Override public File next() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int count; String filename = ze.getName(); File tmpFile = File.createTempFile(filename, "tmp"); tmpFile.deleteOnExit();// TODO make it configurable FileOutputStream fout = new FileOutputStream(tmpFile); while ((count = zis.read(buffer)) != -1) { baos.write(buffer, 0, count); byte[] bytes = baos.toByteArray(); fout.write(bytes); baos.reset(); } fout.close(); zis.closeEntry(); return tmpFile; } catch (Exception e) { throw new RuntimeException(e); } } @Override public void remove() { throw new RuntimeException("not implemented"); } public void close() { try { zis.close(); is.close(); } catch (IOException e) {// nope } } }
最小的例子,我用我的zip文件解压缩到我的应用程序caching文件夹中的特定文件。 然后我使用不同的方法读取清单文件。
private void unzipUpdateToCache() { ZipInputStream zipIs = new ZipInputStream(context.getResources().openRawResource(R.raw.update)); ZipEntry ze = null; try { while ((ze = zipIs.getNextEntry()) != null) { if (ze.getName().equals("update/manifest.json")) { FileOutputStream fout = new FileOutputStream(context.getCacheDir().getAbsolutePath() + "/manifest.json"); byte[] buffer = new byte[1024]; int length = 0; while ((length = zipIs.read(buffer))>0) { fout.write(buffer, 0, length); } zipIs .closeEntry(); fout.close(); } } zipIs .close(); } catch (IOException e) { e.printStackTrace(); } }
使用这个库。
将这个jar文件添加到应用程序的lib文件夹中。
检查你的import这样的
import net.lingala.zip4j.core.ZipFile; import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.model.FileHeader;
像这样使用下面的方法
unzip("/sdcard/file.zip","/sdcard/unzipFolder") public static void unzip(String Filepath, String DestinationFolderPath) { try { ZipFile zipFile = new ZipFile(Filepath); List<FileHeader> fileHeaders = zipFile.getFileHeaders(); for(FileHeader fileHeader : fileHeaders) { String fileName = fileHeader.getFileName(); if (fileName.contains("\\")) { fileName=fileName.replace("\\","\\\\"); String[] Folders=fileName.split("\\\\"); StringBuilder newFilepath=new StringBuilder(); newFilepath.append(DestinationFolderPath); for (int i=0;i< Folders.length-1;i++){ newFilepath.append(File.separator); newFilepath.append(Folders[i]); } zipFile.extractFile(fileHeader, newFilepath.toString(),null,Folders[Folders.length-1]); }else { zipFile.extractFile(fileHeader,DestinationFolderPath); } } } catch (ZipException e) { e.printStackTrace(); } }
密码保护的Zip文件
如果你想用密码压缩文件,你可以看看这个库 ,可以轻松地用密码压缩文件:
压缩:
ZipArchive zipArchive = new ZipArchive(); zipArchive.zip(targetPath,destinationPath,password);
解压缩:
ZipArchive zipArchive = new ZipArchive(); zipArchive.unzip(targetPath,destinationPath,password);
RAR:
RarArchive rarArchive = new RarArchive(); rarArchive.extractArchive(file archive, file destination);
这个库的文档已经足够好了,我只是从那里添加了一些例子。 这是完全免费的,专门为Android写的。