读取jar文件中的zip文件

以前我们的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文件移回核心项目?

entry可以为您提供inner-zip文件的输入流。

 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

顺序拉链访问

当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。 我希望如此,因为当没有更多条目时我不知道其他方式。

TrueZip怎么样? 使用它,您只需打开压缩文件,就好像它位于目录中一样。

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

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

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

我修改了上面提供的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”))

也可以解析字符串并在另一个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; }