2010-09-01 18 views
14

Bir GZip dosyasını açmanıza izin veren birçok işlevi bulabilirim, ancak bir GZip dizesini nasıl açabilirim?Sıkıştırılmış GZip dizgisini Java'da sıkıştır

Yanıt gövdesinin GZip ile sıkıştırıldığı bir HTTP yanıtını ayrıştırmaya çalışıyorum. Ancak, tüm yanıt basitçe bir dizede saklanır, böylece dizenin bir kısmı ikili karakterler içerir.

byte responseBodyBytes[] = responseBody.getBytes(); 
ByteArrayInputStream bais = new ByteArrayInputStream(responseBodyBytes); 
GZIPInputStream gzis = new GZIPInputStream(bais); 

Ama bu sadece bir istisna atar:

kullandığım çalışılıyor java.io.IOException: Değil GZIP formatında

cevap

14

bir GZip dize diye bir şey yoktur içinde. GZip ikilidir, dizeler metinlerdir.

Bir dizgeyi sıkıştırmak isterseniz, onu önce ikiliye dönüştürmeniz gerekir - ör. OutputStreamWriter bir sıkıştırma OutputStream zincirlenmiş olan (örneğin, bir GZIPOutputStream) Benzer şekilde için

bir sıkışıklığını InputStream (örneğin, bir GZIPInputStream) zincirlenmiş bir InputStreamReader kullanabilir, veri okumak.

Reader'dan kolayca okunmanın bir yolu, CharStreams.toString(Readable) numarasını Guava veya benzeri bir kütüphaneden kullanmaktır.

+0

Yanıt gövdesinin GZip ile sıkıştırıldığı bir HTTP yanıtını ayrıştırmaya çalışıyorum. Ancak, tüm yanıt basitçe bir dizede saklanır, böylece dizenin bir kısmı ikili karakterler içerir. Bu "GZip dizesini" bir metin dizesine dönüştürmenin mümkün olmadığını mı söylüyorsunuz? – Matt

+0

@Matt: Yanıtın başlanması için bir dizede saklanmamalısınız. İkiliyse, base64 olmadıkça, metinde olmamalıdır. "Dizenin bir kısmı ikili veri içerir" kavramı gerçekten işe yaramıyor. Yaklaşımını değiştirmen gerekiyormuş gibi geliyor. –

+0

Yanıt başlangıçta bir byte [] olarak sunuldu, yani elimdeki tüm bu var. Bunu kullanabilir miyim? – Matt

1

İdeal olarak, bu şeyleri sizin için halletmek için üst düzey bir kitaplık kullanmalısınız. Bu şekilde, yeni bir HTTP sürümü yayınlandığında, kütüphane yöneticisi umarım tüm zor işleri sizin için yapar ve sadece kütüphanenin güncellenmiş versiyonuna ihtiyacınız vardır.

Bu arada, bunu kendiniz yapmayı denemek için güzel bir egzersiz.

Bir TCP soketinden bir bayt akışı olarak bir HTTP Yanıtı okuduğunuzu varsayalım. Eğer gzip kodlaması yoksa, tüm cevabı bir String'e koymak işe yarayabilir. Bununla birlikte, "Content-Encoding: gzip" başlığının bulunması, yanıt gövdesinin (sizin de belirttiğiniz gibi) ikili olması anlamına gelir.

Yanıt gövdesinin başlangıcını, "\ r \ n \ r \ n" (veya 4 bayt 0x0d, 0x0a, 0x0d, 0x0a) dizesi dizisinin ilk oluşumunu izleyen ilk bayt olarak belirleyebilirsiniz.

gzip kodlaması özel başlık vardır ve bunun için ilk 3 vücut bayt test etmelidir: İlk 3 bayt yoksa

   byte[] buf; // from the HTTP Response stream 
       // ... insert code here to populate buf from HTTP Response stream 
       // ... 
       int bodyLen = 1234; // populate this value from 'Content-length' header 
       int bodyStart = 123; // index of byte buffer where body starts 
       if (bodyLen > 4 && buf[bodyStart] == 0x1f && buf[bodyStart + 1] == (byte) 0x8b && buf[bodyStart + 2] == 0x08) { 
        // gzip compressed body 
        ByteArrayInputStream bais = new ByteArrayInputStream(buf); 
        if (bodyStart > 0) bais.skip(bodyStart); 

        // Decompress the bytes 
        byte[] decompressedBytes = new byte[bodyLen * 4]; 
        int decompressedDataLength = 0; 
        try { 
         // note: replace this try-catch with try-with-resources here where possible 
         GZIPInputStream gzis = new GZIPInputStream(bais); 
         decompressedDataLength = gzis.read(decompressedBytes); 
         gzis.close(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 

"Değil GZIP formatında" hata GZIPInputStream tarafından üretilir Sihirli GZIP üstbilgi değerlerini eşleştirin, bu nedenle bunlara yönelik test yapmak, sorununuzu çözmenize yardımcı olur.

Ayrıca, GZIP biçiminde bir CRC sağlama toplamı vardır, ancak eksik veya yanlışsa, farklı bir hata görmeniz gerekir.

İlgili konular