web-dev-qa-db-fra.com

Compression GZIP en un tableau d'octets

J'essaie d'écrire une classe capable de compresser des données. Le code ci-dessous échoue (aucune exception n'est levée, mais le fichier .gz cible est vide.)
En outre: je ne veux pas générer le fichier .gz directement comme c’est le cas dans tous les exemples. Je veux seulement obtenir les données compresséesdonnées, pour pouvoir par exemple chiffrez-le avant d'écrire les données dans un fichier.

Si j'écris directement dans un fichier, tout fonctionne bien:

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

Mais si je veux le "contourner" dans le flux de tableau d'octets, il ne produit pas un seul octet - compressedData est toujours vide.

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){ }
    }
  }
}
14
Master-Jimmy

Le problème est que vous ne fermez pas la GZIPOutputStream. Tant que vous ne la fermez pas, la sortie sera incomplète.

Vous devez juste le fermer avant lire le tableau d'octets. Pour cela, vous devez réorganiser les blocs 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();
    }
  }
}

Je ne recommande pas d'initialiser les variables de flux à null, car cela signifie que votre bloc finally peut également générer une NullPointerException.

Notez également que vous pouvez déclarer main pour lancer IOException (dans ce cas, vous n’auriez pas besoin de l’énoncé try le plus externe.)

Il ne sert à rien d’avaler les exceptions de zipStream.close();, car s’il lève une exception, vous n’avez pas de fichier .gz valide (vous ne devez donc pas l’écrire.)

De plus, je n’enlèverais pas d’exceptions de byteStream.close(); mais pour une raison différente: elles ne devraient jamais être lancées (c’est-à-dire qu’il ya un bogue dans votre JRE et que vous voudriez être au courant.)

32
finnw

Si vous cherchez toujours une réponse, vous pouvez utiliser le code ci-dessous pour obtenir l'octet compressé [] à l'aide de deflater et le décompresser à l'aide de 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; 
        }   
6
Harikanth

J'ai amélioré le code de JITHINRAJ - used 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;
    }
5
Vladislav Kysliy

Compresser

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

Pour décompresser

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[]{};
    }
0
J.R

Vous pouvez utiliser la fonction ci-dessous, elle est testée et fonctionne bien.

En général, votre code a de sérieux problèmes de ignorant les exceptions! renvoyer null ou simplement ne rien imprimer dans le bloc catch rendra le débogage très difficile

Vous n'êtes pas obligé d'écrire la sortie Zip dans un fichier si vous souhaitez la traiter plus avant (par exemple, la chiffrer), vous pouvez facilement modifier le code pour écrire la sortie dans le flux en mémoire.

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
iTech

Essayez avec ce code ..

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

Peut aussi être utile celui-ci ..

0
ridoy