2010-09-14 95 views
6

以前我们在我们的web应用程序中有一些zip文件。我们想要压缩zip文件中的特定文本文档。这不是一个问题:阅读jar文件中的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文件移回核心项目?

回答

4

条目可以为您提供内部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()返回null时,拉链的结束文件是否到达。我希望如此,因为当没有更多条目时我不知道其他方式来实现。

+0

事实上,你可以使用Class.getResourceAsStream和ZipInputStream阅读外-zip。这样,您就不需要特别的文件名替换,也不需要依赖URL来访问文件。 – helios 2010-09-14 16:30:58

6

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

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

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

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

0

我已经修改了上面提供的顺序邮编接入代码:

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文件到文件系统中的文件夹。 “是”是输入流内的另一个jar文件的JAR文件(jar.getInputStream(“LIB/abcd.jar”))

0

它也可以分析该字符串并且在另一ZipInputStream打开ZipInputStream和将条目设置到文件里面。

例如你有一个像上面的字符串“路径/到/一些-jar.jar /内部/ 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; 
}