2010-09-14 96 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; 
}