Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/199.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在Android中以编程方式解压缩文件?_Java_Android_Unzip - Fatal编程技术网

Java 如何在Android中以编程方式解压缩文件?

Java 如何在Android中以编程方式解压缩文件?,java,android,unzip,Java,Android,Unzip,我需要一个小的代码片段,它从一个给定的.zip文件中解压几个文件,并根据压缩文件中的格式给出单独的文件。请发布你的知识并帮助我 Android内置了Java API。检查包裹 这门课是你应该研究的。从ZipInputStream读取ZipEntry并将其转储到文件系统/文件夹中。检查文件。这是我的解压方法,我使用: private boolean unpackZip(String path, String zipname) { InputStream is; Z

我需要一个小的代码片段,它从一个给定的.zip文件中解压几个文件,并根据压缩文件中的格式给出单独的文件。请发布你的知识并帮助我

Android内置了Java API。检查包裹


这门课是你应该研究的。从ZipInputStream读取ZipEntry并将其转储到文件系统/文件夹中。检查文件。

这是我的解压方法,我使用:

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;
}
这是一个ZipFileIterator(类似于java迭代器,但用于zip文件):

包ch.epfl.bbp.io;
导入java.io.BufferedInputStream;
导入java.io.ByteArrayOutputStream;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileNotFoundException;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.util.Iterator;
导入java.util.zip.ZipEntry;
导入java.util.zip.ZipInputStream;
公共类ZipFileIterator实现了迭代器{
专用字节[]缓冲区=新字节[1024];
私有文件输入流为;
私人Zipinputzis;
私家侦探;
公共ZipFileIterator(文件)引发FileNotFoundException{
is=新文件输入流(文件);
zis=新的ZipInputStream(新的BufferedInputStream(is));
}
@凌驾
公共布尔hasNext(){
试一试{
返回(ze=zis.getNextEntry())!=null;
}捕获(IOE异常){
e、 printStackTrace();
}
返回false;
}
@凌驾
公共文件下一步(){
试一试{
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
整数计数;
字符串文件名=ze.getName();
File tmpFile=File.createTempFile(文件名为“tmp”);
tmpFile.deleteOnExit();//使其可配置
FileOutputStream fout=新的FileOutputStream(tmpFile);
而((计数=zis.read(缓冲区))!=-1){
写入(缓冲区,0,计数);
byte[]bytes=baos.toByteArray();
fout.写入(字节);
重置();
}
fout.close();
zis.closeEntry();
返回tmpFile;
}捕获(例外e){
抛出新的运行时异常(e);
}
}
@凌驾
公共空间删除(){
抛出新的RuntimeException(“未实现”);
}
公众假期结束(){
试一试{
zis.close();
is.close();
}捕获(IOE异常){//nope
}
}
}

对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) 
         {
             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);

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

虽然这里已经给出了很好的答案,但我发现它们比我希望的要慢一些。取而代之的是我使用的,我认为这是最好的解决方案,因为它的速度。它还允许对压缩量进行不同的选择,我发现这很有用

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

 }
->助手类(unzippers.java)

->xml布局(activity_main.xml):


->Menifest文件中的权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

根据瓦西里·索钦斯基的回答,有点小改动&有一个小修正:

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();
    }
}
显著差异

  • 公共静态
    -这是一种可以在任何地方使用的静态实用程序方法
  • 2
    File
    参数,因为
    String
    是:/for files,并且无法指定之前提取zip文件的位置。另外
    path+filename
    concatenation>
  • 抛出
    -因为-如果真的对它们不感兴趣,请添加一个try-catch
  • 实际上,确保所有情况下都存在所需的目录。并非每个zip都包含文件项之前的所有必需目录项。这有两个潜在的bug:
    • 如果zip包含一个空目录,并且结果目录中存在一个现有文件,则会忽略该文件。
      mkdirs()
      的返回值很重要
    • 可能会在不包含目录的zip文件上崩溃
  • 增加了写缓冲区大小,这将稍微提高性能。存储通常以4k块为单位,而以较小的块为单位写入通常比必要的速度慢
  • 使用
    finally
    的魔力来防止资源泄漏
所以

应该做与原作相同的事

unpackZip("/sdcard/", "pictures.zip")

根据@zapl answer,用进度报告解压:

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

使用下面的类

    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" />

我用来将特定文件从zipfile解压到我的应用程序缓存文件夹的最小示例。然后,我使用不同的方法读取清单文件

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

}

受密码保护的Zip文件

val zipFile = File("path_to_your_zip_file")
file.unzip()
如果您想使用密码压缩文件,您可以查看一下可以轻松使用密码压缩文件的:

Zip:

ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);
ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);
RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);
解压缩:

ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);
ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);
RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);
Rar:

ZipArchive zipArchive = new ZipArchive();
zipArchive.zip(targetPath,destinationPath,password);
ZipArchive zipArchive = new ZipArchive();
zipArchive.unzip(targetPath,destinationPath,password);
RarArchive rarArchive = new RarArchive();
rarArchive.extractArchive(file archive, file destination);
这个库的文档已经足够好了,我只是从那里添加了一些示例。 它是完全免费的,专门为android编写。

Kotlin way

//FileExt.kt

data class ZipIO (val entry: ZipEntry, val output: File)

fun File.unzip(unzipLocationRoot: File? = null) {

    val rootFolder = unzipLocationRoot ?: File(parentFile.absolutePath + File.separator + nameWithoutExtension)
    if (!rootFolder.exists()) {
       rootFolder.mkdirs()
    }

    ZipFile(this).use { zip ->
        zip
        .entries()
        .asSequence()
        .map {
            val outputFile = File(rootFolder.absolutePath + File.separator + it.name)
            ZipIO(it, outputFile)
        }
        .map {
            it.output.parentFile?.run{
                if (!exists()) mkdirs()
            }
            it
        }
        .filter { !it.entry.isDirectory }
        .forEach { (entry, output) ->
            zip.getInputStream(entry).use { input ->
                output.outputStream().use { output ->
                    input.copyTo(output)
                }
            }
        }
    }

}
用法

val zipFile = File("path_to_your_zip_file")
file.unzip()

我正在处理Java的ZipFile类无法处理的zip文件。Java8显然无法处理压缩方法12(我相信是bzip2)。在尝试了包括zip4j在内的许多方法(由于另一个问题,zip4j在处理这些特定文件时也会失败)之后,我成功地使用了支持zip4j的Apache commons compress

请注意,下面的ZipFile类不是java.util.zip中的类

它实际上是org.apache.commons.compress.archivers.zip.ZipFile,所以要小心导入

try (ZipFile zipFile = new ZipFile(archiveFile)) {
    Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
    while (entries.hasMoreElements()) {
        ZipArchiveEntry entry = entries.nextElement();
        File entryDestination = new File(destination, entry.getName());
        if (entry.isDirectory()) {
            entryDestination.mkdirs();
        } else {
            entryDestination.getParentFile().mkdirs();
            try (InputStream in = zipFile.getInputStream(entry); OutputStream out = new FileOutputStream(entryDestination)) {
                IOUtils.copy(in, out);
            }
        }
    }
} catch (IOException ex) {
    log.debug("Error unzipping archive file: " + archiveFile, ex);
}

根据zapl的回答,在
Closeable
周围添加
try()
会在使用后自动关闭流

public static void unzip(File zipFile, File targetDirectory) {
    try (FileInputStream fis = new FileInputStream(zipFile)) {
        try (BufferedInputStream bis = new BufferedInputStream(fis)) {
            try (ZipInputStream zis = new ZipInputStream(bis)) {
                ZipEntry ze;
                int count;
                byte[] buffer = new byte[Constant.DefaultBufferSize];
                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;
                    try (FileOutputStream fout = new FileOutputStream(file)) {
                        while ((count = zis.read(buffer)) != -1)
                            fout.write(buffer, 0, count);
                    }
                }
            }
        }
    } catch (Exception ex) {
        //handle exception
    }
}
使用从Jon Skeet的回答中获得的
C#NET 4
中的
Constant.DefaultBufferSize
65536
):

我总是看到帖子使用
byte[1024]
byte[4096]
缓冲区,从来都不知道缓冲区可以大得多,这样可以提高性能,并且仍然正常工作

这是