首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Android ZipInputStream:只有放气的条目才能有EXT描述符

Android ZipInputStream:只有放气的条目才能有EXT描述符
EN

Stack Overflow用户
提问于 2017-11-10 01:38:48
回答 2查看 6.5K关注 0票数 5

在我的android设备上,我需要提取一个从内容uri获取的文件(一个xapk,据我所知,这是一个纯zip压缩文件)。我使用下面这行代码创建ZipInputStream:

代码语言:javascript
复制
ZipInputStream zis = new ZipInputStream(getContentResolver().openInputStream(zipUri));

然后,我尝试用以下命令读取归档文件的第一个条目:

代码语言:javascript
复制
ZipEntry entry = zis.getNextEntry()

问题是我得到了这个异常:

java.util.zip.ZipException:只有经过压缩的条目才能具有EXT描述符

我100%确定归档文件中没有0字节的文件,并且我可以使用设备中的其他实用程序(RAR、解压等)提取相同的归档文件。

如果我使用具有硬编码路径的ZipFile (因此不涉及内容uri ),我可以毫无问题地提取相同的归档文件,因此问题与具有uri的ZipInputStream有关。另一方面,我不能在这里使用ZipFile,因为它不支持内容uris。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-01-17 20:43:58

不幸的是,目前唯一的答案是:

不要像ZipInputStream那样以流模式处理ZIP文件。似乎所有当前可用的压缩处理组件,如JRE的ZipInputStreamApache commons-compressZipArchiveInputStream都不能处理这样的压缩文件。

在apache commons-compress帮助页面上有一个非常好的问题描述:

ZIP存档知道一个叫做数据描述符的特性,它是一种在条目数据之后存储条目长度的方法。只有当大小信息可以从中央目录获取,或者数据本身可以发出完成的信号时,这才能可靠地工作,这对于使用压缩压缩算法压缩的数据是正确的。

ZipFile可以访问中央目录,并且可以使用数据描述符可靠地提取条目。只要条目是空的,ZipArchiveInputStream也是如此。对于存储的条目,ZipArchiveInputStream可以尝试预读,直到找到下一个条目,但是这种方法是不安全的,必须通过构造函数参数显式启用。

https://commons.apache.org/proper/commons-compress/zip.html

解决方案

避免这个问题的唯一可能是使用ZipFile,但是ZipFile实现需要一个真实的文件,因此您可能必须将数据保存到临时文件中。

或者,如果您使用Apache commons-compress中的ZipFile,并且您已经将ZIP文件完全存储在内存中,则可以避免使用SeekableInMemoryByteChannel将其保存到临时文件中。

编辑:使用内存中ZipFile的解决方案(Kotlin):

代码语言:javascript
复制
ByteArrayOutputStream().use { byteArrayOutputStream ->
    inputStream.copyTo(byteArrayOutputStream)
    ZipFile(SeekableInMemoryByteChannel(byteArrayOutputStream.toByteArray())).use {
        for (entry in it.entries) {
            it.getInputStream(entry).copyTo(someOutputStream)
        }
    }
}
票数 11
EN

Stack Overflow用户

发布于 2018-06-16 06:49:14

尝试使用commons-compress

代码语言:javascript
复制
<dependency>
   <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.17</version>
</dependency>

这是一段代码片段

代码语言:javascript
复制
public void unzip(File zipFile, File destDir) throws IOException, ArchiveException {
       String destDirectory = destDir.getAbsolutePath();

       try (ArchiveInputStream i = new ZipArchiveInputStream(new 
          FileInputStream(zipFile), "UTF-8", false, true)) {
          ArchiveEntry entry = null;
          while ((entry = i.getNextEntry()) != null) {
             if (!i.canReadEntryData(entry)) {
                System.out.println("Can't read entry: " + entry);
                continue;
             }
             String name = destDirectory + File.separator + entry.getName();
             File f = new File(name);
             if (entry.isDirectory()) {
                if (!f.isDirectory() && !f.mkdirs()) {
                   throw new IOException("failed to create directory " + f);
                }
             } else {
                File parent = f.getParentFile();
                if (!parent.isDirectory() && !parent.mkdirs()) {
                   throw new IOException("failed to create directory " + parent);
                }
                try (OutputStream o = Files.newOutputStream(f.toPath())) {
                   IOUtils.copy(i, o);
                }
             }
          }
       }
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47208272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档