【问题标题】:Reading a zip file within a jar file在 jar 文件中读取 zip 文件
【发布时间】:2010-09-14 15:57:37
【问题描述】:

以前,我们的 Web 应用程序中有一些 zip 文件。我们希望解析 zip 文件中的特定文本文档。这不是问题:

URL url = getClass().getResource(zipfile);
ZipFile zip = new ZipFile(url.getFile().replaceAll("%20", " "));     
Entry entry = zip.getEntry("file.txt");

InputStream is = zip.getInputStream(entry);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));

String line = reader.readLine();
while (line != null) {
    // do stuff
}

但是,我们已经将这些 zip 文件移动到另一个模块中,并希望将它们打包到一个 jar 中。不幸的是,现在创建 ZipFile 失败了。我可以为 zip 获取 InputStream:但我无法获取条目本身的输入流。

InputStream is = getClass().getResourceAsStream(zipfile);
ZipInputStream zis = new ZipInputStream(is);

ZipEntry entry = zis.getNextEntry();
while (entry != null && !entry.getName().equals("file.txt")) {
    entry = zis.getNextEntry();
}

但我无法获取条目本身的输入流。我尝试查找条目的长度并从 ZipInputStream 获取下一个 n 字节,但这对我不起作用。似乎读取的所有字节都是 0。

有没有办法解决这个问题,还是我必须将 zip 文件移回核心项目?

【问题讨论】:

    标签: java jar zip


    【解决方案1】:

    TrueZip 怎么样?使用它,您可以简单地打开压缩文件,就像它位于目录中一样。

    new FileOutputStream("/path/to/some-jar.jar/internal/zip/file.zip/myfile.txt");
    

    根据文档,还支持无限嵌套。我还没有真正使用过这个项目,但我已经关注了一段时间,它似乎适用于你的问题。

    项目站点:http://truezip.java.net/(已编辑)

    【讨论】:

      【解决方案2】:

      entry 可以为您提供内部压缩文件的输入流。

      InputStream innerzipstream = zip.getInputStream(entry);
      

      所以你可以使用

      new ZipInputStream(innerzipstream);
      

      并要求 ZipInputStream 检索内部 zip 文件的内容(以有序的方式,您没有随机访问权限,因为它是 ZipInputStream)

      看http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html

      顺序 zip 访问

      由于 ZipInputStream 从输入流中读取 zip 文件,它必须按顺序执行操作:

      // DO THIS for each entry
      ZipEntry e = zipInputStreamObj.getNextEntry();
      e.getName // and all data
      int size = e.getSize(); // the byte count
      while (size > 0) {
         size -= zipInputStreamObj.read(...);
      }
      zipInputStreamObj.closeEntry();
      // DO THIS END
      
      zipInputStreamObj.close();
      

      注意:我不知道 ZipInputStream.getNextEntry() 在到达 zip 文件末尾时是否返回 null。我希望如此,因为当没有更多条目时,我不知道其他方式来实现。

      【讨论】:

      • 其实你也可以使用 Class.getResourceAsStream 和 ZipInputStream 来读取外层压缩包。这样,您就不需要临时文件名替换,也不需要依赖 URL 来访问文件。
      【解决方案3】:

      我已经修改了上面提供的 Sequential Zip 访问代码:

      File destFile = new File(destDir, jarName);
      JarOutputStream jos = new JarOutputStream(new FileOutputStream(destFile));
      
      JarInputStream jis = new JarInputStream(is);
      JarEntry jarEntry = jis.getNextJarEntry();
      for (; jarEntry != null ; jarEntry = jis.getNextJarEntry()) {
          jos.putNextEntry(new JarEntry(jarEntry.getName()));
          if(jarEntry.isDirectory()) {
             continue;
          }
      
          int bytesRead = jis.read(buffer);
          while(bytesRead != -1) {
          jos.write(buffer, 0, bytesRead);
          bytesRead = jis.read(buffer);
          }
      
      }
      is.close();
      jis.close();
      jos.flush();
      jos.closeEntry();
      jos.close();
      

      在上面的代码中,我试图将另一个 Jar 文件中的 Jar 文件复制到文件系统中的文件夹中。 'is'是另一个jar文件中jar文件的输入流(jar.getInputStream("lib/abcd.jar"))

      【讨论】:

        【解决方案4】:

        也可以解析字符串并在另一个 ZipInputStream 上打开一个 ZipInputStream 并将条目设置为里面的文件。

        例如你有上面的字符串“path/to/some-jar.jar/internal/zip/file.zip/myfile.txt”

        private static final String[] zipFiles = new String[] { ".zip", ".jar" };
        
        public static InputStream getResourceAsStream(final String ref) throws IOException {
            String abstractPath = ref.replace("\\", "/");
            if (abstractPath.startsWith("/")) {
                abstractPath = abstractPath.substring(1);
            }
            final String[] pathElements = abstractPath.split("/");
            return getResourceAsStream(null, pathElements);
        }
        
        private static InputStream getResourceAsStream(final ZipInputStream parentStream, final String[] pathElements)
                throws IOException {
        
            if (pathElements.length == 0) return parentStream;
        
            final StringBuilder nextFile = new StringBuilder();
            for (int index = 0; index < pathElements.length; index++) {
                final String pathElement = pathElements[index];
                nextFile.append((index > 0 ? "/" : "") + pathElement);
                if (pathElement.contains(".")) {
                    final String path = nextFile.toString();
                    if (checkForZip(pathElement)) {
                        final String[] restPath = new String[pathElements.length - index - 1];
                        System.arraycopy(pathElements, index + 1, restPath, 0, restPath.length);
                        if (parentStream != null) {
                            setZipToEntry(parentStream, path);
                            return getResourceAsStream(new ZipInputStream(parentStream), restPath);
                        } else return getResourceAsStream(new ZipInputStream(new FileInputStream(path)), restPath);
                    } else {
                        if (parentStream != null) {
                            setZipToEntry(parentStream, path);
                            return parentStream;
                        } else return new FileInputStream(path);
                    }
                }
            }
            throw new FileNotFoundException("File not found: " + nextFile.toString());
        }
        
        private static void setZipToEntry(final ZipInputStream in, final String name) throws IOException {
            ZipEntry entry;
            while ((entry = in.getNextEntry()) != null) {
                if (entry.getName().equals(name)) return;
            }
            throw new FileNotFoundException("File not found: " + name);
        }
        
        private static boolean checkForZip(final String ref) {
            for (final String zipFile : zipFiles) {
                if (ref.endsWith(zipFile)) return true;
            }
            return false;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-12-04
          • 1970-01-01
          • 1970-01-01
          • 2013-01-04
          • 2012-10-09
          • 2022-10-04
          • 2011-10-11
          相关资源
          最近更新 更多