2013-02-08 26 views
10

Sto provando a scrivere una classe che può comprimere i dati. Il codice seguente non riesce (non viene generata alcuna eccezione, ma il file .gz di destinazione è vuoto.)
Inoltre: Non voglio generare il file .gz direttamente come è stato fatto in tutti gli esempi. Voglio solo ottenere i dati compressi , in modo che io possa ad es. crittografarlo prima di scrivere i dati su un file.Compressione GZIP su un array di byte

Se scrivo direttamente in un file tutto funziona bene:

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){ } 
    } 
    } 
} 

Ma, se voglio 'bypass' al array di byte streaming non produce un singolo byte - compressedData è sempre vuoto.

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

"* Il codice sottostante non riesce *" non è un messaggio di errore Java valido. –

+0

Si prega di includere anche la traccia dello stack dall'errore. –

+0

Genera semplicemente un file che non è un archivio ZIP. Non c'è nessun messaggio di errore. –

risposta

23

il problema è che non si sta chiudendo il GZIPOutputStream. Finché non lo richiudi, l'output sarà incompleto.

È sufficiente chiuderlo prima di per leggere l'array di byte. È necessario riordinare i blocchi finally per ottenere ciò.

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(); 
    } 
    } 
} 

Non consiglio inititalizing le variabili di flusso per null, perché significa che il blocco finally può anche gettare un NullPointerException.

Si noti inoltre che è possibile dichiarare main gettare IOException (quindi non avrebbe bisogno il più esterno try dichiarazione.)

Non ha molto senso a deglutire eccezioni da zipStream.close();, perché se viene generata un'eccezione non dovrete un file .gz valido (., quindi non si dovrebbe procedere per scriverlo)

anche io non avrei ingoiare eccezioni da byteStream.close(); ma per un motivo diverso - non devono mai essere gettati (cioè v'è un bug nel JRE e si vorrei saperlo.)

+0

Bene, sembra che tu abbia la risposta al mio problema. Grazie! –

+1

So che è vecchio, ma zipStream = zipStream = nel secondo tentativo {} per nessuna ragione apparente. – mangusbrother

0

Prova con questo codice ..

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(); 
} 

Inoltre può essere utile questo ..

+0

Questo codice scrive direttamente in un file ZIP; che è ciò che non voglio Ma grazie comunque. –

0

È possibile utilizzare la funzione qui sotto, è testato e funziona bene.

In generale, il codice ha il problema serio di ignorando le eccezioni! tornando null o semplicemente non stampare nulla nel blocco catch renderà molto difficile eseguire il debug

Non è necessario scrivere l'output zip in un file, se si desidera elaborare ulteriormente (ad esempio cifrare), si può facilmente modificare il codice per scrivere l'output in memoria flusso

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

È possibile aggiungere ciascuna di queste istruzioni 'close()' in un blocco 'try/catch' e ignorare l'errore – iTech

5

Se si sta ancora cercando una risposta, è possibile utilizzare il codice riportato di seguito per ottenere il byte compresso [] utilizzando deflattore e decomprimerlo mediante 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

Grazie amico! Questo era il codice che sto cercando :) – Freshchris

0

Per comprimere

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[]{}; 
    } 

per decomprimere

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

ho migliorato il codice di JITHINRAJ - usato 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; 
    }