2013-05-03 44 views
31

Tôi đang sử dụng mã sau để nén và giải nén dữ liệu chuỗi, nhưng vấn đề mà tôi phải đối mặt là, nó dễ dàng bị nén mà không có lỗi, nhưng phương pháp giải nén sẽ ném lỗi sau.nén và giải nén dữ liệu chuỗi trong java

ngoại lệ trong chủ đề java.io.IOException "chính": Không có trong định dạng 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; 
    } 

Vẫn không thể tìm ra cách để khắc phục vấn đề này !!!

+1

nỗ lực của bạn đánh giá cao, và cảm ơn bạn đã đăng câu hỏi với một chương trình đang chạy. –

Trả lời

30

Đây là vì

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

Gửi byte[] mà bạn có thể nhận được từ ByteArrayOutputStream của bạn và sử dụng nó như vậy trong ByteArrayInputStream của bạn để xây dựng GZIPInputStream của bạn. Sau đây là những thay đổi cần được thực hiện trong mã của bạn.

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

Cũng xem xét việc sử dụng StringBuilder thay vì chỉ ghép nối chuỗi, bởi vì String là bất biến và bạn sẽ lãng phí không gian trong chuỗi.(Các dòng mực tràn về điều này) – fornarat

7

Vấn đề là dòng này:

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

Mảng byte obj chứa dữ liệu nhị phân tùy ý. Bạn không thể "giải mã" dữ liệu nhị phân tùy ý như thể nó là UTF-8. Nếu bạn cố gắng, bạn sẽ nhận được một chuỗi mà sau đó không thể được "mã hóa" trở lại byte. Hoặc ít nhất, các byte bạn nhận được sẽ khác với những gì bạn đã bắt đầu ... đến mức chúng không còn là luồng GZIP hợp lệ nữa.

Khắc phục là lưu trữ hoặc truyền tải nội dung của mảng byte như hiện tại. Đừng cố chuyển nó thành một String. Nó là dữ liệu nhị phân, không phải văn bản.

+0

Tuy nhiên, nếu bạn muốn lưu trữ dữ liệu nén dưới dạng văn bản, bạn có thể đạt được điều này như thế nào? – perrohunter

+3

Sử dụng base64 hoặc một số mã hóa nhị phân dưới dạng văn bản khác. –

11

Nếu bạn đã bao giờ cần phải chuyển các nội dung đã được nén qua mạng hoặc lưu trữ nó dưới dạng văn bản, bạn phải sử dụng Base64 mã hóa (ví dụ như commons apache giải mã Base64) để chuyển đổi mảng byte để một Base64 String, và giải mã chuỗi trở lại mảng byte tại máy khách từ xa. Tìm thấy một ví dụ tại Use Zip Stream and Base64 Encoder to Compress Large String Data!

+0

ví dụ tốt nếu bạn cần chuỗi trong kết quả – demon101

+0

Ví dụ đơn giản nhất tôi đã đi qua chưa cho gzipping. –

17

Câu trả lời ở trên giải quyết vấn đề của chúng tôi nhưng ngoài ra. nếu chúng tôi đang cố gắng giải nén một định dạng không nén ("không phải định dạng zip") byte []. chúng tôi sẽ nhận được thông báo ngoại lệ "Không ở định dạng GZIP".

Để giải quyết chúng tôi có thể thêm mã bổ sung trong Lớp của chúng tôi.

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

Nén Hoàn My Class với nén/giải nén sẽ trông như thế:

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

rất đẹp. bạn đang thiếu một cuộc gọi đến 'gzip.flush();' trước 'gzip.close();' mặc dù. – isapir

+2

cảm ơn vì đã xem xét mã. –

+0

Tôi sử dụng mã của bạn và tôi thêm một sửa đổi nhỏ cho các đường ngắt, trong phương thức giải nén của bạn: 'while ((line = bufferedReader.readLine())! = Null) { \t \t \t \t outStr.append (line); \t \t \t \t outStr.append (System.getProperty ("line.separator")); \t \t \t} ' –

0

Một ví dụ về nén và giải nén đúng:

@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); 
     } 
    } 
} 
Các vấn đề liên quan