2013-08-04 62 views
0

我目前正在嘗試創建一個將幾個ZipFile合併成一個大的方法。因此我創建了一個輸出文件和一個列表InputStream s的方法。Java - 確定一個ZipInputStream是否包含一個條目

這些InputStream s後來轉換成ZipInputStream s。這工作正常!

但是,當文件已被添加到存檔時,我遇到了麻煩。在這一點上,我需要覆蓋已添加的條目(InputStream s具有較高索引(列表中較低)應覆蓋具有較低索引的流中的文件)。我也知道如何做到這一點:如果存檔需要覆蓋它,我只是不添加條目。 但問題是我如何檢查一個條目是否包含在ZipInputStream中,這樣我可以跳過添加當前流的條目?

我迄今爲止代碼:

public static void makeNewZipFromInputStreamList(File outputFile, 
      ArrayList<InputStream> inputStreamList, 
      ArrayList<String> includeList, ArrayList<String> excludeList) 
      throws IOException, IllegalArgumentException { 
     final int sizeOfLists[] = new int[] { inputStreamList.size(), 
       includeList.size(), excludeList.size() }; 

     if ((sizeOfLists[0] != sizeOfLists[1]) 
       || (sizeOfLists[0] != sizeOfLists[2]) 
       || (sizeOfLists[1] != sizeOfLists[2])) 
      throw new IllegalArgumentException(
        "The ArrayLists do not have the same size (" 
          + sizeOfLists[0] + ", " + sizeOfLists[1] + ", " 
          + sizeOfLists[2] + ")"); 

     final ZipOutputStream zipOutputFile = new ZipOutputStream(
       new FileOutputStream(outputFile)); 
     final int size = sizeOfLists[0]; 
     InputStream inputStreamTempArray[] = inputStreamList 
       .toArray(new InputStream[size]); 
     String includeArray[] = includeList.toArray(new String[size]); 
     String excludeArray[] = excludeList.toArray(new String[size]); 

     int i, j; 
     ZipInputStream stream, streamTmp; 
     ZipInputStream inputStreamArray[] = new ZipInputStream[size]; 
     String include, exclude, fileName; 
     ZipEntry entry; 

     for (i = 0; i < size; i++) { 
      inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]); 

      if (includeArray[i] == null) { 
       includeArray[i] = ""; 
      } 

      if (excludeArray[i] == null) { 
       excludeArray[i] = ""; 
      } 
     } 

     for (i = 0; i < size; i++) { 
      while ((entry = inputStreamArray[i].getNextEntry()) != null) { 
       fileName = entry.getName(); 

       for (j = i + 1; j < size; j++) { 
        // Check if the entry exists in the following archives (Then skip this entry) 
       } 

       if (fileName.matches(includeArray[i]) || !fileName.matches(excludeArray[i])) { 
        zipOutputFile.putNextEntry(entry); 

        if (!entry.isDirectory()) { 
         copyStream(inputStreamArray[i], zipOutputFile, false, false); 
        } 
       } 
      } 

      inputStreamArray[i].close(); 
     } 

     zipOutputFile.close(); 
    } 

copyStream:

private static boolean copyStream(final InputStream is, 
      final OutputStream os, boolean closeInputStream, 
      boolean closeOutputStream) { 
     try { 
      final byte[] buf = new byte[1024]; 

      int len = 0; 
      while ((len = is.read(buf)) > 0) { 
       os.write(buf, 0, len); 
      } 

      if (closeInputStream) { 
       is.close(); 
      } 

      if (closeOutputStream) { 
       os.close(); 
      } 

      return true; 
     } catch (final IOException e) { 
      e.printStackTrace(); 
     } 
     return false; 
    } 

編輯:

我有想法,只是追加倒過來意思是從開始的條目列表的末尾,如果一個條目已經被放置,它會跳過。

當我這樣做,我得到一個非常奇怪的錯誤:

java.util.zip.ZipException: invalid entry compressed size (expected 1506 but got 1507 bytes) 
    at java.util.zip.ZipOutputStream.closeEntry(Unknown Source) 
    at java.util.zip.ZipOutputStream.putNextEntry(Unknown Source) 
    at io.brainstone.github.installer.FileUtils.makeNewZipFromInputStreamList(FileUtils.java:304) 
    at io.brainstone.github.installer.Main.startInstalling(Main.java:224) 
    at io.brainstone.github.installer.Window$3$1.run(Window.java:183) 

這是我當前的代碼:

public static void makeNewZipFromInputStreamList(File outputFile, 
      ArrayList<InputStream> inputStreamList, 
      ArrayList<String> includeList, ArrayList<String> excludeList) 
      throws IOException, IllegalArgumentException { 
     final int sizeOfLists[] = new int[] { inputStreamList.size(), 
       includeList.size(), excludeList.size() }; 

     if ((sizeOfLists[0] != sizeOfLists[1]) 
       || (sizeOfLists[0] != sizeOfLists[2]) 
       || (sizeOfLists[1] != sizeOfLists[2])) 
      throw new IllegalArgumentException(
        "The ArrayLists do not have the same size (" 
          + sizeOfLists[0] + ", " + sizeOfLists[1] + ", " 
          + sizeOfLists[2] + ")"); 

     final ZipOutputStream zipOutputFile = new ZipOutputStream(
       new FileOutputStream(outputFile)); 

     final int size = sizeOfLists[0]; 
     final InputStream inputStreamTempArray[] = inputStreamList 
       .toArray(new InputStream[size]); 
     final String includeArray[] = includeList.toArray(new String[size]); 
     final String excludeArray[] = excludeList.toArray(new String[size]); 
     final ZipInputStream inputStreamArray[] = new ZipInputStream[size]; 

     HashMap<String, Object[]> tmp; 

     int i, j; 
     String fileName; 
     ZipEntry entry; 

     for (i = size - 1; i >= 0; i--) { 
      System.out.println(i); 

      inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]); 

      if (includeArray[i] == null) { 
       includeArray[i] = ""; 
      } 

      if (excludeArray[i] == null) { 
       excludeArray[i] = ""; 
      } 

      while ((entry = inputStreamArray[i].getNextEntry()) != null) { 
       fileName = entry.getName(); 

       if (fileName.matches(includeArray[i]) 
         || !fileName.matches(excludeArray[i])) { 
        // Here is where I would check if a entry is already put. 
        // Probably just by catching the exception thrown in this 
        // case 
        zipOutputFile.putNextEntry(entry); 

        if (!entry.isDirectory()) { 
         copyStream(inputStreamArray[i], zipOutputFile, false, 
           false); 
        } 
       } 
      } 

      inputStreamArray[i].close(); 
     } 

     zipOutputFile.close(); 
    } 

回答

0

最簡單的方法來解決,這是通過反向的ArrayList迭代。

public static void makeNewZipFromInputStreamList(File outputFile, 
      ArrayList<InputStream> inputStreamList, 
      ArrayList<String> includeList, ArrayList<String> excludeList) 
      throws IOException, IllegalArgumentException { 
     final int sizeOfLists[] = new int[] { inputStreamList.size(), 
       includeList.size(), excludeList.size() }; 

     if ((sizeOfLists[0] != sizeOfLists[1]) 
       || (sizeOfLists[0] != sizeOfLists[2]) 
       || (sizeOfLists[1] != sizeOfLists[2])) 
      throw new IllegalArgumentException(
        "The ArrayLists do not have the same size (" 
          + sizeOfLists[0] + ", " + sizeOfLists[1] + ", " 
          + sizeOfLists[2] + ")"); 

     final ZipOutputStream zipOutputFile = new ZipOutputStream(
       new FileOutputStream(outputFile)); 

     final int size = sizeOfLists[0]; 
     final InputStream inputStreamTempArray[] = inputStreamList 
       .toArray(new InputStream[size]); 
     final String includeArray[] = includeList.toArray(new String[size]); 
     final String excludeArray[] = excludeList.toArray(new String[size]); 
     final ZipInputStream inputStreamArray[] = new ZipInputStream[size]; 

     HashMap<String, Object[]> tmp; 

     int i, j; 
     String fileName; 
     ZipEntry entry; 

     for (i = size - 1; i >= 0; i--) { 
      inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]); 

      if (includeArray[i] == null) { 
       includeArray[i] = ""; 
      } 

      if (excludeArray[i] == null) { 
       excludeArray[i] = ""; 
      } 

      while ((entry = inputStreamArray[i].getNextEntry()) != null) { 
       fileName = entry.getName(); 

       if (fileName.matches(includeArray[i]) 
         || !fileName.matches(excludeArray[i])) { 
        try { 
         zipOutputFile.putNextEntry(entry); 

         if (!entry.isDirectory()) { 
          copyStream(inputStreamArray[i], zipOutputFile, 
            false, false); 
         } 
        } catch (ZipException ex) { 
         if (!ex.getMessage() 
           .matches("duplicate entry: .*\\..*")) { 
          throw new RuntimeException(
            "Unexpected " + ex.getClass() + " (\"" 
              + ex.getMessage() 
              + "\")\n(only duplicate entry execptions are expected!)", 
            ex); 
         } 
        } 
       } 
      } 

      inputStreamArray[i].close(); 
     } 

     zipOutputFile.close(); 
    } 

但無論如何謝謝你!

0
  1. 按住地圖從fileNameentry
  2. 迭代所有輸入流中的所有條目,並將條目放在映射中,按文件名映射。上次輸入將始終覆蓋前一個。完成後,每個文件名只有所有索引最高的條目。
  3. 迭代地圖的條目並將它們放到zipOutputFile

    // (1) here all entries will be stored, overriding low-indexed with high-indexed 
    final Map<String, ZipEntry> fileNameToZipEntry = new HashMap<String, ZipEntry>(); 
    
    // (2) Iterate over all entries and store in map, overriding low-indexed 
    for (i = 0; i < size; i++) { 
    
        while ((entry = inputStreamArray[i].getNextEntry()) != null) { 
         fileName = entry.getName(); 
         fileNameToZipEntry.put(fileName, entry); 
        } 
    
        inputStreamArray[i].close(); 
    } 
    
    // (3) Iterating the map that holds only the entries required for zipOutputFile 
    int j = 0; 
    for (Set<Map.Entry<String, ZipEntry>> mapEntry : fileNameToZipEntry.entrySet()) { 
    
        if (fileName.matches(includeArray[j]) || !fileName.matches(excludeArray[j])) { 
    
         zipOutputFile.putNextEntry(entry); 
    
         if (!entry.isDirectory()) { 
          copyStream(inputStreamArray[j], zipOutputFile, false, false); 
         } 
        } 
        j++; 
    } 
    
+0

這個想法非常好!但是不能以這種方式實現,因爲在第一次迭代完畢後,您忘記了ZipInputStream已經結束了。你也忘了變量'i'不能在第二個for循環中使用。 – BrainStone

+0

@YannickSchinko好吧,你有想法然後:)。出於清晰的原因,我儘可能簡潔地說明。 – yair

+0

@YannickSchinko不用等一下,第二次迭代**不會超過'ZipInputStream',而是在地圖**上。 – yair

相關問題