2012-03-03 122 views
3

我想壓縮/解壓縮和序列化/反序列化String內容。我正在使用以下兩個靜態函數。使用deflater壓縮/解壓縮字符串

/** 
* Compress data based on the {@link Deflater}. 
* 
* @param pToCompress 
*   input byte-array 
* @return compressed byte-array 
* @throws NullPointerException 
*    if {@code pToCompress} is {@code null} 
*/ 
public static byte[] compress(@Nonnull final byte[] pToCompress) { 
    checkNotNull(pToCompress); 

    // Compressed result. 
    byte[] compressed = new byte[] {}; 

    // Create the compressor. 
    final Deflater compressor = new Deflater(); 
    compressor.setLevel(Deflater.BEST_SPEED); 

    // Give the compressor the data to compress. 
    compressor.setInput(pToCompress); 
    compressor.finish(); 

    /* 
    * Create an expandable byte array to hold the compressed data. 
    * You cannot use an array that's the same size as the orginal because 
    * there is no guarantee that the compressed data will be smaller than 
    * the uncompressed data. 
    */ 
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream(pToCompress.length)) { 
     // Compress the data. 
     final byte[] buf = new byte[1024]; 
     while (!compressor.finished()) { 
      final int count = compressor.deflate(buf); 
      bos.write(buf, 0, count); 
     } 

     // Get the compressed data. 
     compressed = bos.toByteArray(); 
    } catch (final IOException e) { 
     LOGWRAPPER.error(e.getMessage(), e); 
     throw new RuntimeException(e); 
    } 


    return compressed; 
} 

/** 
* Decompress data based on the {@link Inflater}. 
* 
* @param pCompressed 
*   input string 
* @return compressed byte-array 
* @throws NullPointerException 
*    if {@code pCompressed} is {@code null} 
*/ 
public static byte[] decompress(@Nonnull final byte[] pCompressed) { 
    checkNotNull(pCompressed); 

    // Create the decompressor and give it the data to compress. 
    final Inflater decompressor = new Inflater(); 
    decompressor.setInput(pCompressed); 

    byte[] decompressed = new byte[] {}; 

    // Create an expandable byte array to hold the decompressed data. 
    try (final ByteArrayOutputStream bos = new ByteArrayOutputStream(pCompressed.length)) { 
     // Decompress the data. 
     final byte[] buf = new byte[1024]; 
     while (!decompressor.finished()) { 
      try { 
       final int count = decompressor.inflate(buf); 
       bos.write(buf, 0, count); 
      } catch (final DataFormatException e) { 
       LOGWRAPPER.error(e.getMessage(), e); 
       throw new RuntimeException(e); 
      } 
     } 
     // Get the decompressed data. 
     decompressed = bos.toByteArray(); 
    } catch (final IOException e) { 
     LOGWRAPPER.error(e.getMessage(), e); 
    } 

    return decompressed; 
} 

然而,比起非壓縮值是數量級慢即使我緩存解壓縮,結果,如果在真正需要的內容值僅解壓縮。

也就是說,它用於類似於DOM的持久化樹結構和XPath查詢,這些強制解壓縮String值的速度大約是50倍(如果不是更慢)(不是真正的基準測試,只是執行單元測試) 。我的筆記本電腦甚至在一些單元測試(每次檢查約5次)後都會凍結,因爲Eclipse由於繁重的I/O而不再響應,甚至沒有響應。我甚至將壓縮等級設置爲Deflater.BEST_SPEED,而其他壓縮等級可能會更好,也許我提供的配置選項參數可以設置爲resources。也許我已經搞砸了,因爲我之前沒有使用過deflater。考慮到Deflater實例解壓到一個靜態字段後似乎創造deflater的實例,吹氣是非常昂貴的性能瓶頸:我在字符串lenght爲> 10

編輯我甚至只有壓縮內容已經消失了,也許沒有microbenchmarks或類似的東西,我看不到任何性能損失:-)我只是在使用新的輸入之前重置了deflater/inflater。

+0

你是如何測量壓縮和解壓縮算法的性能的?你能分享一下你的想法/代碼嗎?你計算算法的壓縮比和壓縮時間嗎?如果是這樣,請你與我分享經驗?我已經爲隨機字符串實現了壓縮和解壓縮算法,現在我需要通過計算壓縮比,壓縮時間等來測量算法的性能。任何幫助都將被讚賞。謝謝! – 2014-06-27 03:30:32

回答

2

你如何考慮使用像Gzip這樣的更高級別的API。

下面是一個例子壓縮:

public static byte[] compressToByte(final String data, final String encoding) 
    throws IOException 
{ 
    if (data == null || data.length == 0) 
    { 
     return null; 
    } 
    else 
    { 
     byte[] bytes = data.getBytes(encoding); 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     GZIPOutputStream os = new GZIPOutputStream(baos); 
     os.write(bytes, 0, bytes.length); 
     os.close(); 
     byte[] result = baos.toByteArray(); 
     return result; 
    } 
} 

下面是解壓縮的例子:

public static String unCompressString(final byte[] data, final String encoding) 
    throws IOException 
{ 
    if (data == null || data.length == 0) 
    { 
     return null; 
    } 
    else 
    { 
     ByteArrayInputStream bais = new ByteArrayInputStream(data); 
     ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
     GZIPInputStream is = new GZIPInputStream(bais); 
     byte[] tmp = new byte[256]; 
     while (true) 
     { 
      int r = is.read(tmp); 
      if (r < 0) 
      { 
       break; 
      } 
      buffer.write(tmp, 0, r); 
     } 
     is.close(); 

     byte[] content = buffer.toByteArray(); 
     return new String(content, 0, content.length, encoding); 
    } 
} 

我們得到非常良好的性能和壓縮比與此有關。

zip api也是一個選項。

0

您的評論是正確的答案。

通常情況下,如果要頻繁使用某個方法,則需要消除任何分配和數據複製。這通常意味着將實例初始化和其他設置移除到靜態變量或構造函數。

使用靜力學比較容易,但是您可能遇到生命期問題(如何知道何時清理靜態 - 它們是否永遠存在?)。

在構造函數中進行設置和初始化允許類的用戶確定對象的生命週期並進行適當的清理。您可以在進入處理循環之前將其實例化一次,並在退出後對其進行GC處理。