简体   繁体   English

GZIP 压缩成字节数组

[英]GZIP compression to a byte array

I am trying to write a class that can compress data.我正在尝试编写一个可以压缩数据的类。 The below code fails (no exception is thrown, but the target .gz file is empty.)下面的代码失败(没有抛出异常,但目标 .gz 文件是空的。)
Besides: I don't want to generate the .gz file directly like it is done in all examples.此外:我不想像在所有示例中那样直接生成 .gz 文件。 I only want to get the compressed data, so that I can eg encrypt it before writting the data to a file.我只想获取压缩数据,以便我可以在将数据写入文件之前对其进行加密。

If I write directly to a file everything works fine:如果我直接写入文件,一切正常:

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

But, if I want to 'bypass' it to the byte array stream it does not produce a single byte - compressedData is always empty.但是,如果我想将它“绕过”到字节数组流,它不会产生单个字节 - compressedData数据始终为空。

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

The problem is that you are not closing the GZIPOutputStream .问题是您没有关闭GZIPOutputStream Until you close it the output will be incomplete.在您关闭它之前,输出将是不完整的。

You just need to close it before reading the byte array.您只需要读取字节数组之前关闭它。 You need to reorder the finally blocks to achieve this.您需要重新排序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();
    }
  }
}

I do not recommend inititalizing the stream variables to null , because it means your finally block can also throw a NullPointerException .我不建议将流变量初始化为null ,因为这意味着您的finally块也可以抛出NullPointerException

Also note that you can declare main to throw IOException (then you would not need the outermost try statement.)另请注意,您可以声明main以抛出IOException (然后您将不需要最外层的try语句。)

There is little point in swallowing exceptions from zipStream.close();zipStream.close();中吞下异常没有什么意义zipStream.close(); , because if it throws an exception you will not have a valid .gz file (so you should not proceed to write it.) ,因为如果它抛出异常,您将没有有效的 .gz 文件(因此您不应继续编写它。)

Also I would not swallow exceptions from byteStream.close();我也不会吞下byteStream.close();异常byteStream.close(); but for a different reason - they should never be thrown (ie there is a bug in your JRE and you would want to know about that.)但出于不同的原因 - 它们不应该被抛出(即您的 JRE 中有一个错误,您想知道这一点。)

I've improved JITHINRAJ's code - used try-with-resources :我改进了 JITHINRAJ 的代码 - 使用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);
            // You need to close it before using bos
            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;
    }

If you are still looking an answer you can use the below code to get the compressed byte[] using deflater and decompress it using inflater.如果您仍在寻找答案,您可以使用以下代码使用 deflater 获取压缩的 byte[] 并使用 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; 
        }   

To compress压缩

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

To uncompress解压

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

You can use the below function, it is tested and working fine.您可以使用以下功能,它已经过测试并且工作正常。

In general, your code has serious problem of ignoring the exceptions!一般来说,您的代码存在忽略异常的严重问题! returning null or simply not printing anything in the catch block will make it very difficult to debug返回null或根本不在catch块中打印任何内容将使调试变得非常困难

You do not have to write the zip output to a file if you want to process it further (eg encrypt it), you can easily modify the code to write the output to in-memory stream如果您想进一步处理它(例如加密它),您不必将 zip 输出写入文件,您可以轻松修改代码以将输出写入内存流

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

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

Also may be helpful this one..也可能对这个有帮助..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM