2012-06-11 13 views
5

Mam problem w postaci kodu:GZIP dekompresji ciąg bajtów i konwersja

private static String compress(String str) 
{ 
    String str1 = null; 
    ByteArrayOutputStream bos = null; 
    try 
    { 
     bos = new ByteArrayOutputStream(); 
     BufferedOutputStream dest = null; 

     byte b[] = str.getBytes(); 
     GZIPOutputStream gz = new GZIPOutputStream(bos,b.length); 
     gz.write(b,0,b.length); 
     bos.close(); 
     gz.close(); 

    } 
    catch(Exception e) { 
     System.out.println(e); 
     e.printStackTrace(); 
    } 
    byte b1[] = bos.toByteArray(); 
    return new String(b1); 
} 

private static String deCompress(String str) 
{ 
    String s1 = null; 

    try 
    { 
     byte b[] = str.getBytes(); 
     InputStream bais = new ByteArrayInputStream(b); 
     GZIPInputStream gs = new GZIPInputStream(bais); 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     int numBytesRead = 0; 
     byte [] tempBytes = new byte[6000]; 
     try 
     { 
      while ((numBytesRead = gs.read(tempBytes, 0, tempBytes.length)) != -1) 
      { 
       baos.write(tempBytes, 0, numBytesRead); 
      } 

      s1 = new String(baos.toByteArray()); 
      s1= baos.toString(); 
     } 
     catch(ZipException e) 
     { 
      e.printStackTrace(); 
     } 
    } 
    catch(Exception e) { 
     e.printStackTrace(); 
    } 
    return s1; 
} 

public String test() throws Exception 
    { 
     String str = "teststring"; 
     String cmpr = compress(str); 
     String dcmpr = deCompress(cmpr); 
} 

ten kod throw java.io.IOException: nieznany format (magiczna liczba ef1f)

GZIPInputStream gs = new GZIPInputStream(bais); 

Okazuje się, że podczas konwersji bajtów new String (b1) i byte b [] = str.getBytes() bajtów są "zepsute". Na wyjściu linii mamy już więcej bajtów. Jeśli unikniesz konwersji na ciąg i pracujesz na linii z bajtami - wszystko działa. Przepraszam za mój angielski.


public String unZip(String zipped) throws DataFormatException, IOException { 
    byte[] bytes = zipped.getBytes("WINDOWS-1251"); 
    Inflater decompressed = new Inflater(); 
    decompressed.setInput(bytes); 

    byte[] result = new byte[100]; 
    ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 

    while (decompressed.inflate(result) != 0) 
     buffer.write(result); 

    decompressed.end(); 

    return new String(buffer.toByteArray(), charset); 
} 

Jestem Funkcja ta służy do dekompresji serwera responce. Dzięki za pomoc.

Odpowiedz

7

mieć dwa problemy:

  • używasz domyślnego kodowania znaków do konwertowania oryginalnego ciąg znaków w bajtach. To zależy od platformy. Lepiej podać kodowanie - zazwyczaj dobrym pomysłem jest UTF-8.
  • Próbujesz reprezentować nieprzezroczyste dane binarne wyniku kompresji jako ciąg przez wywołanie konstruktora String(byte[]). Ten konstruktor jest przeznaczony tylko dla danych, które są zakodowanymi tekstami ... które to nie są. Powinieneś użyć base64 do tego. Jest public domain base64 library, co ułatwia to. (Alternatywnie, nie konwertuj skompresowanych danych na tekst w ogóle - po prostu zwróć tablicę bajtów.)

Zasadniczo musisz zrozumieć, jak różne są dane tekstowe i binarne - kiedy chcesz przekonwertować między dwoma , powinieneś to zrobić ostrożnie. Jeśli chcesz reprezentować dane binarne "non-text" (tj. Bajty które nie są bezpośrednim wynikiem kodowania tekstu) w łańcuchu, powinieneś użyć czegoś takiego jak base64 lub hex. Kiedy chcesz zakodować ciąg znaków jako dane binarne (np. Aby zapisać tekst na dysk), powinieneś dokładnie rozważyć, którego kodowania użyć. Jeśli inny program będzie czytał twoje dane, musisz dowiedzieć się, jakiego kodowania oczekuje - jeśli masz nad nim pełną kontrolę, zwykle korzystam z UTF-8.

Dodatkowo, obsługa wyjątków w kodzie jest słaba:

  • Należy prawie nigdy nie złapać Exception; złap więcej konkretnych wyjątków
  • Nie powinieneś po prostu uchwycić wyjątku i kontynuować, jak gdyby nigdy się nie wydarzył. Jeśli nie można naprawdę obsłużyć wyjątek i nadal z powodzeniem zakończyć swoją metodę, należy pozwolić bańki Up wyjątku stosu (lub ewentualnie złapać go i owinąć go w bardziej odpowiedni typ wyjątku dla abstrakcji)
+0

Używam default_charset() == "UTF-8". To tylko test. –

+0

@AlexandrErofeev: Nie będzie jasne, czy ktokolwiek * czyta * Kod, który kodujesz, którego używasz. IMO znacznie lepiej jest podać to wprost. (A jeśli jest to tylko test, całkowicie usuń wszystkie wyjątki i po prostu pozwól wszystkim metodom rzucić 'IOException' - to uprości kod.) –

2

Kiedy GZIP kompresuje dane, zawsze dostajesz dane binarne. Dane te nie mogą zostać przekształcone w ciąg znaków, ponieważ nie zawierają poprawnych danych znakowych (w dowolnym kodowaniu).

Więc metoda kompres powinien zwracać tablicę bajtów i metoda dekompresji powinny podjąć tablicy bajtowej jako parametr.

Co więcej, zalecam stosowanie jawnego kodowania podczas konwertowania ciągu znaków na tablicę bajtów przed kompresją i ponownego przekształcenia zdekompresowanych danych w ciąg znaków.

+0

Fakt, że to tylko test. W rzeczywistości, z serwera, otrzymuję ciąg json, który będzie kluczowym "zip". Zawierające skompresowane dane. Mogę pobrać zawartość klucza jako ciąg. Następnie muszę wyodrębnić te informacje. –

+0

@AlexandrErofeev: Wszystko to jest informacja, którą powinieneś uwzględnić w pytaniu. Podejrzewam, że JSON zawiera dane zakodowane na podstawie base64 ... w ten sposób mogłem * mieć nadzieję *, że reprezentowałoby dane binarne. –

+0

JSON nie może bezpośrednio zawierać danych binarnych. Więc jeśli klucz jest zakodowany GZIP, prawdopodobnie jest również zakodowany w Base64, aby przekształcić dane binarne w ciąg znaków, który może zawierać JSON. Powinieneś prawdopodobnie dodać próbkę JSON z kluczem do twojego pytania. – Codo

0

Podczas kompresji danych GZIP zawsze otrzymujesz dane binarne. Te dane nie mogą zostać przekształcone w ciąg znaków, ponieważ nie są to poprawne dane znakowe (w kodowaniu) w .

Codo ma rację, wielkie dzięki za oświecenie mnie. Próbowałem zdekompresować ciąg znaków (przekonwertowany z danych binarnych). To, co zmieniłem, to użycie InflaterInputStream bezpośrednio w strumieniu wejściowym zwróconym przez moje połączenie http. (Moja aplikacja pobierała duży JSON ciągów znaków)