2013-02-08 12 views
10

Próbuję napisać klasę, która może kompresować dane. Poniższy kod kończy się niepowodzeniem (nie jest zgłaszany wyjątek, ale docelowy plik .gz jest pusty).
Poza tym: Nie chcę generować pliku .gz bezpośrednio, tak jak w przypadku wszystkich przykładów. Chcę tylko uzyskać skompresowane dane, które umożliwią mi np. zaszyfruj go przed zapisaniem danych do pliku.Kompresja GZIP do tablicy bajtów

Jeśli piszę bezpośrednio do pliku wszystko działa poprawnie:

import java.io.*; 
import java.util.zip.*; 
import java.nio.charset.*; 

public class Zipper 
{ 
    public static void main(String[] args) 
    {  
    byte[] dataToCompress = "This is the test data." 
     .getBytes(StandardCharsets.ISO_8859_1); 

    GZIPOutputStream zipStream = null; 
    FileOutputStream fileStream = null; 
    try 
    { 
     fileStream = new FileOutputStream("C:/Users/UserName/Desktop/zip_file.gz"); 
     zipStream = new GZIPOutputStream(fileStream); 
     zipStream.write(dataToCompress); 

     fileStream.write(compressedData); 
    } 
    catch(Exception e) 
    { 
     e.printStackTrace(); 
    } 
    finally 
    { 
     try{ zipStream.close(); } 
     catch(Exception e){ } 
     try{ fileStream.close(); } 
     catch(Exception e){ } 
    } 
    } 
} 

Ale jeśli chcę „obejścia” go do tablicy bajtów strumieniowo go nie wytwarzać jeden bajt - compressedData jest zawsze pusty.

import java.io.*; 
import java.util.zip.*; 
import java.nio.charset.*; 

public class Zipper 
{ 
    public static void main(String[] args) 
    {  
    byte[] dataToCompress = "This is the test data." 
     .getBytes(StandardCharsets.ISO_8859_1); 
    byte[] compressedData = null; 

    GZIPOutputStream zipStream = null; 
    ByteArrayOutputStream byteStream = null; 
    FileOutputStream fileStream = null; 
    try 
    { 
     byteStream = new ByteArrayOutputStream(dataToCompress.length); 
     zipStream = new GZIPOutputStream(byteStream); 
     zipStream.write(dataToCompress); 

     compressedData = byteStream.toByteArray(); 

     fileStream = new FileOutputStream("C:/Users/UserName/Desktop/zip_file.gz"); 
     fileStream.write(compressedData); 
    } 
    catch(Exception e) 
    { 
     e.printStackTrace(); 
    } 
    finally 
    { 
     try{ zipStream.close(); } 
     catch(Exception e){ } 
     try{ byteStream.close(); } 
     catch(Exception e){ } 
     try{ fileStream.close(); } 
     catch(Exception e){ } 
    } 
    } 
} 
+3

"* Poniższy kod kończy się niepowodzeniem *" nie jest prawidłowym komunikatem o błędzie Java. –

+0

Dołącz także ślad stosu z błędu. –

+0

Po prostu generuje plik, który nie jest archiwum ZIP. Nie ma komunikatu o błędzie. –

Odpowiedz

23

problem polega na tym, że nie zamykając GZIPOutputStream. Dopóki go nie zamkniesz, dane wyjściowe będą niekompletne.

Po prostu trzeba go zamknąć przed odczytywanie tablicy bajtów. Aby to osiągnąć, musisz zmienić kolejność bloków finally.

import java.io.*; 
import java.util.zip.*; 
import java.nio.charset.*; 

public class Zipper 
{ 
    public static void main(String[] args) 
    {  
    byte[] dataToCompress = "This is the test data." 
     .getBytes(StandardCharsets.ISO_8859_1); 

    try 
    { 
     ByteArrayOutputStream byteStream = 
     new ByteArrayOutputStream(dataToCompress.length); 
     try 
     { 
     GZIPOutputStream zipStream = 
      new GZIPOutputStream(byteStream); 
     try 
     { 
      zipStream.write(dataToCompress); 
     } 
     finally 
     { 
      zipStream.close(); 
     } 
     } 
     finally 
     { 
     byteStream.close(); 
     } 

     byte[] compressedData = byteStream.toByteArray(); 

     FileOutputStream fileStream = 
     new FileOutputStream("C:/Users/UserName/Desktop/zip_file.gz"); 
     try 
     { 
     fileStream.write(compressedData); 
     } 
     finally 
     { 
     try{ fileStream.close(); } 
      catch(Exception e){ /* We should probably delete the file now? */ } 
     } 
    } 
    catch(Exception e) 
    { 
     e.printStackTrace(); 
    } 
    } 
} 

Nie polecam inititalizing zmienne strumieniowych do null, ponieważ oznacza to, że blok finally może również rzucić NullPointerException.

Należy również pamiętać, że można zadeklarować main rzucać IOException (wtedy nie musiałby zewnętrzną try oświadczenie.)

Nie ma sensu w połykaniu wyjątki od zipStream.close();, bo jeśli zgłasza wyjątek nie będzie miał poprawny plik .gz (więc nie powinieneś kontynuować pisania).

Również nie połknę wyjątków od byteStream.close();, ale z innego powodu - nigdy nie powinny być rzucane (np. jest błąd w twoim środowisku JRE i ty chciałbym o tym wiedzieć.)

+0

Wygląda na to, że masz odpowiedź na mój problem. Dziękuję Ci! –

+1

Wiem, że to stary, ale trzeba zipStream = zipStream = w drugim try {} bez wyraźnego powodu. – mangusbrother

0

Spróbuj z tym kodem ..

try { 
    String inputFileName = "test.txt"; //may use your file_Path 
    String zipFileName = "compressed.zip"; 

    //Create input and output streams 
    FileInputStream inStream = new FileInputStream(inputFileName); 
    ZipOutputStream outStream = new ZipOutputStream(new FileOutputStream(zipFileName)); 

    // Add a zip entry to the output stream 
    outStream.putNextEntry(new ZipEntry(inputFileName)); 

    byte[] buffer = new byte[1024]; 
    int bytesRead; 

    //Each chunk of data read from the input stream 
    //is written to the output stream 
    while ((bytesRead = inStream.read(buffer)) > 0) { 
     outStream.write(buffer, 0, bytesRead); 
    } 

    //Close zip entry and file streams 
    outStream.closeEntry(); 

    outStream.close(); 
    inStream.close(); 

} catch (IOException ex) { 
    ex.printStackTrace(); 
} 

także mogą być pomocne w tym jeden ..

+0

Ten kod zapisuje bezpośrednio do pliku ZIP; czego nie chcę. Ale i tak dziękuję. –

0

Można użyć funkcji poniżej, jest testowany i działa dobrze.

Generalnie Twój kod ma poważny problem z ignorowaniem wyjątków od! zwracanie null lub po prostu nie drukowanie czegokolwiek w bloku bardzo utrudni debugowanie

Nie musisz zapisywać danych wyjściowych zip do pliku, jeśli chcesz go przetworzyć dalej (np. zaszyfrować), możesz łatwo zmodyfikować kod do zapisu danych wyjściowych do strumienia w pamięci

public static String zip(File inFile, File zipFile) throws IOException {   
    FileInputStream fis = new FileInputStream(inFile); 
    FileOutputStream fos = new FileOutputStream(zipFile); 
    ZipOutputStream zout = new ZipOutputStream(fos); 

    try { 
     zout.putNextEntry(new ZipEntry(inFile.getName())); 
     byte[] buffer = new byte[BUFFER_SIZE]; 
     int len; 
     while ((len = fis.read(buffer)) > 0) { 
      zout.write(buffer, 0, len); 
     } 
     zout.closeEntry(); 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
     return null; 
    } finally { 
     try{zout.close();}catch(Exception ex){ex.printStackTrace();} 
     try{fis.close();}catch(Exception ex){ex.printStackTrace();}   
    } 
    return zipFile.getAbsolutePath(); 
} 
+0

Możliwe jest dodanie każdej z tych instrukcji 'close()' w bloku 'try/catch' i zignorowanie błędu. – iTech

5

Jeśli nadal szuka odpowiedzi można użyć poniższy kod, aby uzyskać sprężone byte [] przy użyciu deflater i rozpakować go przy inflater.

public static void main(String[] args) { 
     //Some string for testing 
     String sr = new String("fsdfesfsfdddddddsfdsfssdfdsfdsfdsfdsfdsdfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghghghghggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggfsdfesfsfdddddddsfdsfssdfdsfdsfdsfdsfdsdfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghghghghggggggggggggggggggggggggggggggggggggggggg"); 
     byte[] data = sr.getBytes(); 
     System.out.println("src size "+data.length); 
     try { 
      compress(data); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
    public static byte[] compress(byte[] data) throws IOException { 
     Deflater deflater = new Deflater(); 
     deflater.setInput(data); 
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); 

     deflater.finish(); 
     byte[] buffer = new byte[1024]; 
     while (!deflater.finished()) { 
     int count = deflater.deflate(buffer); 
     outputStream.write(buffer, 0, count); 
     } 
     outputStream.close(); 
     byte[] output = outputStream.toByteArray(); 

     System.out.println("Original: " + data.length ); 
     System.out.println("Compressed: " + output.length); 
     return output; 
     } 
+0

Dzięki człowieku! To był kod, którego szukam :) – Freshchris

0

Aby skompresować

private static byte[] compress(byte[] uncompressedData) { 
     ByteArrayOutputStream bos = null; 
     GZIPOutputStream gzipOS = null; 
     try { 
      bos = new ByteArrayOutputStream(uncompressedData.length); 
      gzipOS = new GZIPOutputStream(bos); 
      gzipOS.write(uncompressedData); 
      gzipOS.close(); 
      return bos.toByteArray(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     finally { 
      try { 
       assert gzipOS != null; 
       gzipOS.close(); 
       bos.close(); 
      } 
      catch (Exception ignored) { 
      } 
     } 
     return new byte[]{}; 
    } 

Aby rozpakować

private byte[] uncompress(byte[] compressedData) { 
     ByteArrayInputStream bis = null; 
     ByteArrayOutputStream bos = null; 
     GZIPInputStream gzipIS = null; 

     try { 
      bis = new ByteArrayInputStream(compressedData); 
      bos = new ByteArrayOutputStream(); 
      gzipIS = new GZIPInputStream(bis); 

      byte[] buffer = new byte[1024]; 
      int len; 
      while((len = gzipIS.read(buffer)) != -1){ 
       bos.write(buffer, 0, len); 
      } 
      return bos.toByteArray(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     finally { 
      try { 
       assert gzipIS != null; 
       gzipIS.close(); 
       bos.close(); 
       bis.close(); 
      } 
      catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     return new byte[]{}; 
    } 
3

mam ulepszony kod JITHINRAJ za - stosowany try-with-resources:

private static byte[] gzipCompress(byte[] uncompressedData) { 
     byte[] result = new byte[]{}; 
     try (ByteArrayOutputStream bos = new ByteArrayOutputStream(uncompressedData.length); 
      GZIPOutputStream gzipOS = new GZIPOutputStream(bos)) { 
      gzipOS.write(uncompressedData); 
      gzipOS.close(); 
      result = bos.toByteArray(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return result; 
    } 

private static byte[] gzipUncompress(byte[] compressedData) { 
     byte[] result = new byte[]{}; 
     try (ByteArrayInputStream bis = new ByteArrayInputStream(compressedData); 
      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
      GZIPInputStream gzipIS = new GZIPInputStream(bis)) { 
      byte[] buffer = new byte[1024]; 
      int len; 
      while ((len = gzipIS.read(buffer)) != -1) { 
       bos.write(buffer, 0, len); 
      } 
      result = bos.toByteArray(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return result; 
    } 
Powiązane problemy