2013-03-20 12 views
8

Mam prosty kod do rozpakowywania plików zip, działało dobrze, jak się spodziewałem, ale podczas testu wypróbowałem mój kod z niektórymi plikami zip (czcionki, ikony i szablony pobrane z Internet), żeby upewnić się należy wyodrębnić wszystkie pliki zip pod warunkiem, ale jej nie działa z niektórych plików zip, tutaj jest zminimalizowane kod zregenerować ten problem:ZipInputStream.getNextEntry zwraca null na niektórych plikach zip

package com.test.mytest; 

import java.io.FileInputStream; 
import java.util.Enumeration; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipFile; 
import java.util.zip.ZipInputStream; 

public class ZipExtractTest { 

    public static final String ZIP_FILE = "/Users/XXXXX/Downloads/janne.zip"; 

    public static void main(String[]args) { 
     unzipFile(ZIP_FILE); 
     unzipStream(ZIP_FILE); 
    } 

    public static void unzipFile(String zipName) { 
     try { 

      ZipFile zf = new ZipFile(zipName); 

      Enumeration ent = zf.entries(); 

      while(ent.hasMoreElements()) { 
       System.out.println(ent.nextElement()); 
      } 

     } catch(Exception e) { 
      System.out.println(e); 
     } 
    } 

    public static void unzipStream(String zipName) { 
     try { 
      ZipInputStream zis = new ZipInputStream(new FileInputStream(zipName)); 
      ZipEntry ze = zis.getNextEntry(); 

      if(ze == null) { 
       System.out.println("unable to get first entry from zip file"); 
       zis.close(); 
       return; 
      } 

      while(ze != null) { 
       System.out.println("Entry Found: " + ze); 
       ze = zis.getNextEntry(); 
      } 

      zis.closeEntry(); 
      zis.close(); 

     } catch(Exception e) { 
      System.out.println(e); 
     } 
    } 
} 

rzeczywiście moim rzeczywistej aplikacji muszę rozpakować zip pliki za pośrednictwem danych wejściowych. W powyższym kodzie próbuję wyodrębnić "janne.zip" Pobrałem ten plik z http://www.iconian.com/fonts/janne.zip Jestem w stanie wyodrębnić go za pomocą dowolnego narzędzia zip i zaskakująco poprzez metodę "unzipFile (String zipName)", ale z unzipStream (String zipName) metoda

ZipEntry ze = zis.getNextEntry(); 

zwraca null

Każda pomoc będzie mile widziane

+0

Huh. To dziwne. +1 dla SSCCE i link do przykładowego pliku. –

+0

Zamknij 'ZipFile' w swojej metodzie' unzipFile' -> [http://docs.oracle.com/javase/1.5.0/docs/api/java/util/zip/ZipFile.html#close%28%29 ] (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/zip/ZipFile.html#close%28%29) – Eich

+0

@da_re to tylko kod demonstracyjny do regeneracji problem z nullem i zamknięcie nie będą miały wpływu na problem, który próbowałem tutaj wskazać. –

Odpowiedz

13

nie odpowiedź, dlaczego ten konkretny plik nie działa z java.util.zip, ale jeśli masz możliwość, aby zastąpić użycie java.util.zip.ZipInputStream z Apache commons-compressorg.apache.commons.compress.archivers.zip.ZipArchiveInputStream (który powinien być zgodny z API), to właśnie przetestowałem to na przykładowym pliku i wygląda na to, że działa poprawnie.

Generalnie uważam, że commons-compress jest dużo bardziej niezawodny niż java.util.zip podczas rozpakowywania plików utworzonych przez narzędzia inne niż same klasy java.util.zip.

Edit: Zrobiłem trochę debugowania w Eclipse i wygląda na to dany plik zip ma single segment spanning marker z 0x30304b50 przed podpisaniem LOC (0x04034b50) lokalnego nagłówka pierwszego wpisu za. To jest coś, co kompiluje commons-knows how to handle, ale java.util.zip nie - jeśli j.u.z.ZipInputStream widzi coś innego niż sygnatura LOC, to wtedy getNextEntry() zwróci null.

+0

Dzięki Roberts, to dziwne. Myślę, że pójdę z twoją sugestią i na pewno spróbuję API commons-compress, ponieważ szukam jakiegoś niezawodnego API dekompresyjnego. Dzięki jeszcze raz! –

+1

Wspaniale, że wróciłeś, aby odpowiedzieć na oryginalne pytanie, +1 Właśnie uratowałeś mi kilka godzin poszukiwań. – avanderw

4

Zabawne!

Po debugowaniu kodu otrzymałem ten sam błąd. Znalazłem sprawdzenie nagłówka w implementacji ZipInputStream, ale nie w implementacji ZipFile.

Nie pytaj mnie dlaczego, ale nagłówek w Twoim pliku zip jest nieważny!

Your file is starting with: 50 4B 30 30 50 4B 03 04 
A valid Zip File Header is: 50 4B 03 04 

Jeśli usuniesz pierwszych bajtów (50 4B 30 30) z pliku masz poprawny nagłówek można przeczytać złożyć!

+0

Rzeczywiście jest to śmieszne! a problem polega na tym, że muszę dostarczyć tę implementację komuś, kto w ogóle nie zna takich rzeczy jak nagłówki plików. On jest jak, jeśli jestem w stanie wyodrębnić plik zip przy użyciu standardowych narzędzi, to dlaczego nie za pośrednictwem kodu. W każdym razie Dzięki - jestem w stanie wydobyć to poprzez Apache commons-compress nawet z takimi nagłówkami –

0


Miałem ten sam problem! Na szczęście dla mnie udało mi się to rozwiązać.
Najpierw resetuję dane blobu w bazie danych, a następnie użyłem kodu java, aby skompresować go za pomocą ZipInputStream. Chociaż nie jestem pewien, problem ZipEntry o wartości zerowej może być spowodowany dwoma czynnikami:
1. Dane blobu w bazie danych nie są poprawnie przechowywane (lub mogą być już skompresowane, niektóre bazy danych kompresują dane blobowe w czasie przechowywania. możesz też to zrobić w Google).
2.Strumienie wejścia/wyjścia może również powodować problemy, zobacz this


Oto szczegółowy opis tego, co zrobiłem:
1. zresetować pola BLOB w bazie danych przy użyciu EMPTY_BLOB i zatwierdzić zmiany
2. użył poniżej Program Java do aktualizacji pola blob z pliku .xls

DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver()); // register driver 

Connection conn = 
    DriverManager.getConnection ("jdbc:oracle:thin:@my-local-database:1521:test", "test1", "test1"); 

// It's faster when auto commit is off: 
conn.setAutoCommit (false); 

try 
{ 
     PreparedStatement pstmt = conn.prepareStatement("update content set file_content = ? where CONTENT_ID=2006"); 
     File blob = new File("C:/Users/ankur/Desktop/Book1.xls"); 
     FileInputStream in = new FileInputStream(blob); 

     pstmt.setBinaryStream(1, in); 
     pstmt.executeUpdate(); 
     conn.commit(); 
     conn.close(); 
     System.out.println("file updated"); 
} 
catch (SQLException e) 
{ 
    e.printStackTrace(); 
} 

Proszę zwrócić uwagę, że powyższy kod będzie działać, ale to absolutnie nie wykazywać standardów kodowania i praktyk.
3. Używane poniżej metody zip kompresji danych

public byte[] zipByteArray(String primaryKey, byte[] input) throws IOException{ 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ZipOutputStream zos = new ZipOutputStream(baos); 
    ZipEntry entry = new ZipEntry(primaryKey); 
    entry.setSize(input.length); 
    zos.putNextEntry(entry); 
    zos.write(input); 
    zos.closeEntry(); 
    zos.close(); 
    return baos.toByteArray(); 
} 

Powyższy sposób wykonuje szereg bajtów, zamki nie stawia go na ByteArrayOutputStream. Możesz użyć samego ByteArrayOutputStream, z powodu pewnych wymagań konwertuję go na tablicę bajtów.
4. Następnie wstaw powyższą tablicę bajtów w polu blob za pomocą przygotowanej instrukcji
5. Jeśli użyję kodu unzip podanego poniżej, działa poprawnie!

public byte[] unzipInputStream(InputStream is) throws IOException { 
    ByteArrayOutputStream byteArrayOutputStream = null; 
    ZipInputStream zipIs = new ZipInputStream(new BufferedInputStream(is)); 
    byteArrayOutputStream = new ByteArrayOutputStream(); 
    ZipEntry entry = zipIs.getNextEntry(); 
    while (entry != null) { 
     byte[] tmp = new byte[2048]; 
     BufferedOutputStream bos = null; 
     bos = new BufferedOutputStream(byteArrayOutputStream); 
     int size = 0; 
     while ((size = zipIs.read(tmp)) != -1) { 
      bos.write(tmp, 0, size); 
     } 
     bos.flush(); 
     bos.close(); 
     entry = zipIs.getNextEntry(); 
    } 
    zipIs.close(); 
    return byteArrayOutputStream.toByteArray(); 

Dane wyjściowe powyższej metody to dane rozpakowane.

Powiązane problemy