2016-04-15 3 views
2

Я использую AsyncTask для распаковки файла, и все, кажется, идет хорошо (все файлы в архиве ZIP извлекаются), но мой метод распаковки никогда не заканчивается.Unzipping with ZipInputStream никогда не заканчивается

Вот источник для моего распакованный класса:

public class MyUnzipper { 


    public static boolean unzipFileIntoDirectory(String inputFilename, String outputPath) throws Exception { 
     ZipInputStream zis = null; 
     BufferedOutputStream dest = null; 

     try { 
      File archive = new File(inputFilename); 
      File destinationDir = new File(outputPath); 

      final int BUFFER_SIZE = 1024; 

      zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(archive), BUFFER_SIZE)); 
      ZipEntry entry = null; 
      File destFile; 
      while((entry = zis.getNextEntry()) != null){ 

       destFile = new File(destinationDir, entry.getName()); 

       if(entry.isDirectory()){ 
        destFile.mkdirs(); 
       } 
       else { 
        // check for and create parent directories if they don't exist 
        File parentDir = destFile.getParentFile(); 
        if (null != parentDir) { 
         if (!parentDir.isDirectory()) { 
          parentDir.mkdirs(); 
         } 
        } 

        int count; 
        byte data[] = new byte[BUFFER_SIZE]; 
        dest = new BufferedOutputStream(new FileOutputStream(destFile), BUFFER_SIZE); 
        Log.i("MyUnzipper", "Beginning unzip of " + destFile); 

        while((count = zis.read(data, 0, BUFFER_SIZE)) != -1){ 
         dest.write(data, 0, count); 
         Log.v("MyUnzipper", "Count = " + count); 
        } 
        dest.flush(); 
        dest.close(); 
        dest = null; 
       } 

       zis.closeEntry(); 

       Log.wtf("MyUnzipper", "Unzipped entry " + entry.getName()); 
      } 

      Log.wtf("MyUnzipper", "Unzip done"); 
     } 
     catch(Exception e){ 
      Log.wtf("MyUnzipper", "Unzip error"); 
      e.printStackTrace(); 
      return false; 
     } 
     finally { 
      if(null != zis) 
       zis.close(); 

      if(null != dest) 
       dest.close(); 
     } 

     return true; 
    } 

} 

Когда я отлаживать эту строку за строкой, он прекрасно работает, пока не распакованы все файлы, то он попадает в zis.closeEntry(), и отладчик просто " уходит ", т.е. следующая строка (Log.wtf(...)) никогда не выполняется. Моя AsyncTask никогда не заканчивается, это как если бы я застрял в бесконечном цикле ?! Но глядя на источник для ZipInputStream.closeEntry(), похоже, там нет никаких петель или чего-то подозрительного?

Я также попытался извлекая архив ZIP с помощью ZipFile вместо ZipInputStream, но затем я получаю следующее сообщение об ошибке:

java.util.zip.ZipException: End Of Central Directory signature not found 

Там нет ничего плохого с файлом ZIP, я проверил его с zip -v -T на Mac OSX. Я также попробовал перемасштабировать его, используя ZIP версии 3.0 и 2.1 (оригинал был 2.0). Я могу распаковать всю версию без каких-либо проблем в Mac OSx (используя утилиту Unarchiver и Archive).

Это сводит меня с ума, что может быть неправильным?

 

Update (решена)

Оказывается, чтобы быть действительно глупая проблема, на самом деле не связанную с разархивирования.

Я загрузив ZIP файлы с сервера, прежде чем расстегивать их, и, видимо, я забыл позвонить close() на выходе потока из операции загрузки перед началом работы распаковать.

Возможно, эта тема может помочь кому-то, кто совершает ту же самую глупую ошибку.

+0

'имя String = entry.getName(); zis.closeEntry(); Log.wtf (... name); 'может быть? Без понятия. –

+0

Проблема заключается в том, что выполнение никогда не достигает 'Log.wtf (...)' для последнего файла, оно каким-то образом не пропускает его после 'closeEntry()' ... так что просто выводит имена первых 11 файлов. – BadCash

+1

Используете ли вы Android [ZipInputStream] (https://developer.android.com/reference/java/util/zip/ZipInputStream.html)?Вероятно, [ZipArchiveInputStream] (https://commons.apache.org/proper/commons-compress/apidocs/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.html) из Apache Commons будет работать в вашем случае. –

ответ

4

Ну, иногда ваш код распаковки ZIP может застрять, даже если вы закрываете все предыдущие выходные и входные потоки. И это a known bug: ZipInputStream#read может возвращать 0.

Дополнение:

Если файл ZIP содержит несколько файлов с именами файлов без ACSII, вы будете сталкиваться с проблемой извлечения. Android ZipInputStream не работает с UTF-8, CP437 и так далее.

В этом случае Apache Commons должно быть решение:

private boolean unpack(File zipFile, File targetDir) { 
    ZipFile zip = null; 
    try { 
     zip = new ZipFile(zipFile.getAbsoluteFile()); 
     final Enumeration<ZipArchiveEntry> entries = zip.getEntries(); 
     while(entries.hasMoreElements()) { 
      ZipArchiveEntry entry = entries.nextElement(); 
      if (entry.isDirectory()) { 
       mkdirsOrThrow(new File(targetDir, entry.getName())); 
       continue; 
      } 
      final File entryDestination = new File(targetDir, entry.getName()); 
      mkdirsOrThrow(entryDestination.getParentFile()); 
      final InputStream in = zip.getInputStream(entry); 
      final OutputStream out = new FileOutputStream(entryDestination); 
      IOUtils.copy(in, out); 
      IOUtils.closeQuietly(in); 
      IOUtils.closeQuietly(out); 
     } 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } finally { 
     if (zip!= null) try { 
      zip.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    return true; 
} 
Смежные вопросы