天天看點

gzip壓縮資料變大_使用GZIP和壓縮資料

gzip壓縮資料變大_使用GZIP和壓縮資料

gzip壓縮資料變大

抽象

我們都知道用zip或gzip壓縮檔案的含義。 但是在Java中使用壓縮檔案并不像您想的那樣簡單明了,尤其是如果您不是直接處理檔案而是壓縮流資料的話。 我們會去:

  • 如何将字元串轉換為壓縮/壓縮位元組數組,反之亦然
  • 建立用于讀取和寫入檔案的實用程式功能,而無需事先知道檔案或流是否已gzip壓縮。

基礎

那麼,為什麼要壓縮任何東西? 很簡單,因為這是減少必須通過網絡傳送或存儲到磁盤的資料量的好方法,是以可以提高操作速度。 根據文檔的性質,典型的文本檔案或消息可以減少10倍或更多。 當然,您将不得不考慮壓縮和解壓縮的成本,但是當您擁有大量資料時,這些成本将不會很大。

Java支援嗎?

是的,Java支援在java.util.zip包中讀寫gzip檔案。 它還支援zip檔案以及流行的ZLIB壓縮庫的資料膨脹和縮小。

如何壓縮/解壓縮Java字元串?

這是一個如何使用DeflaterOutputStream壓縮和解壓縮String的示例。

這是使用Java内置壓縮器的兩種方法以及使用GZIP的方法:

  1. 使用DeflaterOutputStream是最簡單的方法:
    enum StringCompressor {
            ;
            public static byte[] compress(String text) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                try {
                    OutputStream out = new DeflaterOutputStream(baos);
                    out.write(text.getBytes("UTF-8"));
                    out.close();
                } catch (IOException e) {
                    throw new AssertionError(e);
                }
                return baos.toByteArray();
            }
    
            public static String decompress(byte[] bytes) {
                InputStream in = new InflaterInputStream(new ByteArrayInputStream(bytes));
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                try {
                    byte[] buffer = new byte[8192];
                    int len;
                    while((len = in.read(buffer))>0)
                        baos.write(buffer, 0, len);
                    return new String(baos.toByteArray(), "UTF-8");
                } catch (IOException e) {
                    throw new AssertionError(e);
                }
            }
        }
               
  2. 如果要直接使用充氣機/充氣機:
    enum StringCompressor2 {
            ;
            public static byte[] compress(String text) throws Exception{
                byte[] output = new byte;
                Deflater compresser = new Deflater();
                compresser.setInput(text.getBytes("UTF-8"));
                compresser.finish();
                int compressedDataLength = compresser.deflate(output);
                byte[] dest = new byte[compressedDataLength];
                System.arraycopy(output, 0, dest, 0, compressedDataLength);
                return dest;
            }
    
            public static String decompress(byte[] bytes) throws Exception{
                Inflater decompresser = new Inflater();
                decompresser.setInput(bytes, 0, bytes.length);
                byte[] result = new byte[bytes.length *10];
                int resultLength = decompresser.inflate(result);
                decompresser.end();
    
                // Decode the bytes into a String
                String outputString = new String(result, 0, resultLength, "UTF-8");
                return outputString;
            }
        }
               
  3. 使用GZIP的方法如下:
    enum StringGZipper {
            ;
            private static String ungzip(byte[] bytes) throws Exception{
                InputStreamReader isr = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(bytes)), StandardCharsets.UTF_8);
                StringWriter sw = new StringWriter();
                char[] chars = new char[1024];
                for (int len; (len = isr.read(chars)) > 0; ) {
                    sw.write(chars, 0, len);
                }
                return sw.toString();
            }
    
            private static byte[] gzip(String s) throws Exception{
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                GZIPOutputStream gzip = new GZIPOutputStream(bos);
                OutputStreamWriter osw = new OutputStreamWriter(gzip, StandardCharsets.UTF_8);
                osw.write(s);
                osw.close();
                return bos.toByteArray();
            }
        }
               

如何解碼位元組流以允許GZip和普通流:

下面的代碼将位元組流轉換為String(轉儲),而無需事先知道該流是否已壓縮。

if (isGZIPStream(bytes)) {
            InputStreamReader isr = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(bytes)), StandardCharsets.UTF_8);
            StringWriter sw = new StringWriter();
            char[] chars = new char[1024];
            for (int len; (len = isr.read(chars)) > 0; ) {
                sw.write(chars, 0, len);
            }
            dump = sw.toString();
        } else {
            dump = new String(bytes, 0, length, StandardCharsets.UTF_8);
        }
}
           

這是isGZIPStream方法的實作。 揭示關于GZIP_MAGIC背後的真相!

public static boolean isGZIPStream(byte[] bytes) {
        return bytes[0] == (byte) GZIPInputStream.GZIP_MAGIC 
         && bytes[1] == (byte) (GZIPInputStream.GZIP_MAGIC >>> 8);
}
           

這是一種在不知道檔案是否已壓縮的情況下讀取檔案的簡單方法(依賴于擴充名.gz)。

static Stream<String> getStream(String dir, @NotNull String fileName) 
  throws IOException {
        File file = new File(dir, fileName);
        InputStream in;
        if (file.exists()) {
            in = new FileInputStream(file);
        } else {
            file = new File(dir, fileName + ".gz");
            in = new GZIPInputStream(new FileInputStream(file));
        }

        return new BufferedReader(new InputStreamReader(in)).lines();
}
           
翻譯自: https://www.javacodegeeks.com/2015/01/working-with-gzip-and-compressed-data.html

gzip壓縮資料變大