2013-05-03 181 views
31

我使用下面的代碼來壓縮和解壓縮字符串數據,但我面臨的問題是,它很容易被壓縮而沒有錯誤,但解壓縮方法會拋出以下錯誤。在java中的字符串數據的壓縮和解壓縮

異常線程「main」 java.io.IOException異常:非gzip格式

public static void main(String[] args) throws Exception { 
     String string = "I am what I am hhhhhhhhhhhhhhhhhhhhhhhhhhhhh" 
       + "bjggujhhhhhhhhh" 
       + "rggggggggggggggggggggggggg" 
       + "esfffffffffffffffffffffffffffffff" 
       + "esffffffffffffffffffffffffffffffff" 
       + "esfekfgy enter code here`etd`enter code here wdd" 
       + "heljwidgutwdbwdq8d" 
       + "skdfgysrdsdnjsvfyekbdsgcu" 
       +"jbujsbjvugsduddbdj"; 

     System.out.println("after compress:"); 
     String compressed = compress(string); 
     System.out.println(compressed); 
     System.out.println("after decompress:"); 
     String decomp = decompress(compressed); 
     System.out.println(decomp); 
    } 


    public static String compress(String str) throws Exception { 
     if (str == null || str.length() == 0) { 
      return str; 
     } 
     System.out.println("String length : " + str.length()); 
     ByteArrayOutputStream obj=new ByteArrayOutputStream(); 
     GZIPOutputStream gzip = new GZIPOutputStream(obj); 
     gzip.write(str.getBytes("UTF-8")); 
     gzip.close(); 
     String outStr = obj.toString("UTF-8"); 
     System.out.println("Output String length : " + outStr.length()); 
     return outStr; 
    } 

     public static String decompress(String str) throws Exception { 
     if (str == null || str.length() == 0) { 
      return str; 
     } 
     System.out.println("Input String length : " + str.length()); 
     GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(str.getBytes("UTF-8"))); 
     BufferedReader bf = new BufferedReader(new InputStreamReader(gis, "UTF-8")); 
     String outStr = ""; 
     String line; 
     while ((line=bf.readLine())!=null) { 
      outStr += line; 
     } 
     System.out.println("Output String lenght : " + outStr.length()); 
     return outStr; 
    } 

仍然無法弄清楚如何解決這個問題!

+1

你的努力表示讚賞,並感謝您與正在運行的程序發佈的問題。 – 2015-12-10 08:22:01

回答

30

這是因爲

String outStr = obj.toString("UTF-8"); 

發送byte[],你可以從你的ByteArrayOutputStream獲得並使用它作爲這樣在你的ByteArrayInputStream來構建你的GZIPInputStream。以下是需要在代碼中完成的更改。

byte[] compressed = compress(string); //In the main method 

public static byte[] compress(String str) throws Exception { 
    ... 
    ... 
    return obj.toByteArray(); 
} 

public static String decompress(byte[] bytes) throws Exception { 
    ... 
    GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes)); 
    ... 
} 
+9

另外考慮使用StringBuilder,而不是隻是連接字符串,因爲字符串是不可變的,你將浪費字符串池中的空間。(墨水溢出來) – fornarat 2014-03-13 22:38:14

7

問題是這樣的線:

String outStr = obj.toString("UTF-8"); 

的字節數組obj包含任意的二進制數據。您不能像任何UTF-8一樣「解碼」任意的二進制數據。如果你嘗試,你會得到一個字符串,不能被編碼回字節。或者至少,您獲得的字節將與您開始使用的字節不同,因爲它們不再是有效的GZIP流。

修正是按原樣存儲或傳輸字節數組的內容。不要試圖將其轉換爲字符串。它是二進制數據,而不是文本。

+0

但是,如果您想將壓縮數據作爲文本存儲,您如何實現這一目標? – perrohunter 2013-08-26 17:46:18

+3

使用base64或其他二進制文本編碼。 – 2013-08-26 22:43:35

11

如果您需要通過網絡將壓縮傳輸內容或將其保存爲文本,你必須使用的Base64編碼器(如Apache公地編解碼器的Base64)字節數組轉換爲Base64編碼字符串,和解碼該字符串返回到遠程客戶端的字節數組。 在Use Zip Stream and Base64 Encoder to Compress Large String Data找到一個示例!

+0

很好的例子,如果你需要字符串結果 – demon101 2015-07-21 18:27:18

+0

我曾經遇到過的最直接的例子是gzip。 – 2016-11-09 15:10:44

17

上述答案解決了我們的問題,但除此之外。 如果我們試圖解壓縮一個未壓縮的(「不是zip格式」)byte []。 我們會得到「Not in GZIP format」例外信息。

爲了解決這個問題,我們可以在我們的類中添加額外的代碼。

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

我完全壓縮類具有壓縮/解壓縮會是什麼樣子:

import java.io.BufferedReader; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.util.zip.GZIPInputStream; 
import java.util.zip.GZIPOutputStream; 

public class GZIPCompression { 
    public static byte[] compress(final String str) throws IOException { 
    if ((str == null) || (str.length() == 0)) { 
     return null; 
    } 
    ByteArrayOutputStream obj = new ByteArrayOutputStream(); 
    GZIPOutputStream gzip = new GZIPOutputStream(obj); 
    gzip.write(str.getBytes("UTF-8")); 
    gzip.flush(); 
    gzip.close(); 
    return obj.toByteArray(); 
    } 

    public static String decompress(final byte[] compressed) throws IOException { 
    final StringBuilder outStr = new StringBuilder(); 
    if ((compressed == null) || (compressed.length == 0)) { 
     return ""; 
    } 
    if (isCompressed(compressed)) { 
     final GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(compressed)); 
     final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gis, "UTF-8")); 

     String line; 
     while ((line = bufferedReader.readLine()) != null) { 
     outStr.append(line); 
     } 
    } else { 
     outStr.append(compressed); 
    } 
    return outStr.toString(); 
    } 

    public static boolean isCompressed(final byte[] compressed) { 
    return (compressed[0] == (byte) (GZIPInputStream.GZIP_MAGIC)) && (compressed[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8)); 
    } 
} 
+0

非常好。你在'gzip.close();'之前錯過了對'gzip.flush();'的調用。 – isapir 2017-06-18 23:59:47

+2

感謝您審查代碼。 – 2017-06-19 08:27:01

+0

我使用你的代碼,我在你的解壓縮方法中添加了一些修正行爲:while((line = bufferedReader.readLine())!= null)。 \t \t \t \t outStr.append(System.getProperty(「line.separator」)); \t \t \t}' – 2017-11-15 09:41:41

0

正確的壓縮和解壓縮又如:

@Slf4j 
public class GZIPCompression { 
    public static byte[] compress(final String stringToCompress) { 
     if (isNull(stringToCompress) || stringToCompress.length() == 0) { 
      return null; 
     } 

     try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      final GZIPOutputStream gzipOutput = new GZIPOutputStream(baos)) { 
      gzipOutput.write(stringToCompress.getBytes(UTF_8)); 
      gzipOutput.finish(); 
      return baos.toByteArray(); 
     } catch (IOException e) { 
      throw new UncheckedIOException("Error while compression!", e); 
     } 
    } 

    public static String decompress(final byte[] compressed) { 
     if (isNull(compressed) || compressed.length == 0) { 
      return null; 
     } 

     try (final GZIPInputStream gzipInput = new GZIPInputStream(new ByteArrayInputStream(compressed)); 
      final StringWriter stringWriter = new StringWriter()) { 
      IOUtils.copy(gzipInput, stringWriter, UTF_8); 
      return stringWriter.toString(); 
     } catch (IOException e) { 
      throw new UncheckedIOException("Error while decompression!", e); 
     } 
    } 
}