2015-09-01 2 views
1

Когда я пытаюсь вычислить «на лету» MD5 zip-файла и разархивировать его в одно и то же время, для некоторого zip-файла он не работает: сумма MD5 неверна, хотя файл не поврежден.ZipInputStream и DigestInputStream не работают вместе

Вот отрывок из моего кода:

MessageDigest lMd = MessageDigest.getInstance("MD5"); 

FileOutputStream lFos = null; 
try (DigestInputStream lDis = new DigestInputStream(lListener.getInputStream(), lMd); 
          ZipInputStream lZip = new ZipInputStream(lDis)) { 

    // Read the response content 
    //get the zipped file list entry 
    ZipEntry lZipEntry = lZip.getNextEntry(); 

    while (lZipEntry != null) { 
     String lFileName = lZipEntry.getName(); 

     File lNewFile = new File(UPDATE_FOLDER + File.separator + lFileName); 

     if (lZipEntry.isDirectory()) { 
      lNewFile.mkdirs(); 
     } else { 
      //create all non exists folders 
      new File(lNewFile.getParent()).mkdirs(); 

      lFos = new FileOutputStream(lNewFile);    

      int lRead; 
      while ((lRead = lZip.read(lBuffer)) > -1) { 
       lFos.write(lBuffer, 0, lRead); 
      } 

      lFos.close(); 
     } 

     lZipEntry = lZip.getNextEntry(); 
    } 

    lZip.closeEntry(); 
} finally { 
    if (lFos != null) { 
     lFos.close(); 
} 
         byte[] lDigest = lMd.digest(); 

        StringBuffer lHexString = new StringBuffer(); 
        for (int lI = 0; lI < lDigest.length; lI++) { 
         if ((0xFF & lDigest[lI]) < 0x10) { 
          lHexString.append("0" 
            + Integer.toHexString((0xFF & lDigest[lI]))); 
         } else { 
          lHexString.append(Integer.toHexString(0xFF & lDigest[lI])); 
         } 
        } 
        String lDigestStr = lHexString.toString(); 

Можете ли вы мне помочь?

Спасибо! aGO!

+0

Почему вы объявляете 'FileOutputStream lFos' снаружи? Вы знаете, как использовать try-with-resources, поэтому используйте его на 'new FileOutputStream'. – Andreas

+1

'lZip.closeEntry()' бессмысленно. По крайней мере, сейчас у вас это есть. – Andreas

+0

Так как вам нравится цикл-в-while для вашего внутреннего цикла, почему бы не использовать внешний цикл? – Andreas

ответ

0

Вам необходимо отделить две операции. ZipInputStream не построен, чтобы полностью потреблять базовый поток. Причиной этого является ZIP формат файла, который в основном выглядит следующим образом:

<file header><file data> 
<file header><file data> 
<file header><file data> 
<...> 
<last file header><last file data> 
<directory header> 
<directory header> 
<directory header> 
<...> 
<last directory header> 

<file header> и <directory header> имеют разные подписи. Вот что ZipInputStream делает, когда getNextEntry() называется:

if (get32(tmpbuf, 0) != LOCSIG) { 
    return null; 
} 

Это подтверждает, что буфер он только что прочитал начинается с символов «PK \ 003 \ 004», который был бы правильный заголовок файла. Однако, как только каталог заголовков запуска, это будет начать возвращать null, потому что заголовки каталогов являются «PK \ 001 \ 002.»

После этого ZipInputStream вернется null из getNextEntry(), после чего вы будете остановить ее потребления. Единственное решение для вашей конкретной проблемы - сначала проверить файл, а затем распаковать его. Как уже упоминалось в комментариях, вы должны сделать это так или иначе, потому что вы должны обязательно не использовать файл, если проверка не удалась!