2012-06-11 4 views
5

Tengo un problema en el código:GZIP y el byte de conversión

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); 
} 

Este java.io.IOException código de tiro: formato desconocido (número mágico ef1f)

GZIPInputStream gs = new GZIPInputStream(bais); 

Resulta que al convertir el byte new String (b1) y byte b [] = str.getBytes() los bytes están "dañados". En la salida de la línea ya tenemos más bytes. Si evita la conversión a una cadena y trabaja en línea con bytes, todo funciona. Lo siento por mi ingles.


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); 
} 

estoy utilización de esta función para descomprimir responce servidor. Gracias por la ayuda.

Respuesta

7

usted tiene dos problemas:

  • que está utilizando la codificación de caracteres por defecto para convertir la cadena original en bytes. Eso variará según la plataforma. Es mejor especificar una codificación: UTF-8 suele ser una buena idea.
  • Está intentando representar los datos binarios opacos del resultado de la compresión como una cadena simplemente llamando al constructor String(byte[]). Ese constructor es solo destinado a datos que son texto codificado ... que esto no es. Deberías usar base64 para esto. Hay un public domain base64 library que lo hace fácil. (Alternativamente, no convierta los datos comprimidos a texto; simplemente devuelva una matriz de bytes.)

Fundamentalmente, debe entender cómo son diferentes los datos de texto y binarios, cuando desea convertir entre los dos , deberías hacerlo con cuidado. Si desea representar datos binarios "no textuales" (es decir, bytes que no son el resultado directo de la codificación de texto) en una cadena, debe usar algo como base64 o hexadecimal. Cuando desee codificar una cadena como datos binarios (por ejemplo, para escribir texto en el disco), debe considerar cuidadosamente qué codificación usar. Si otro programa va a leer tus datos, debes averiguar qué codificación espera: si tienes el control total sobre ti, normalmente elegiría UTF-8.

Además, el manejo de excepciones en el código es pobre: ​​

  • Debe ponerse casi nunca Exception; atrape las excepciones más específicas
  • No solo debe atrapar una excepción y continuar como si nunca hubiera sucedido. Si realmente no se puede manejar la excepción y todavía completar su método con éxito, usted debe dejar que la burbuja de excepción en la pila (o, posiblemente, cogerlo y lo envuelve en un tipo de excepción más apropiado para su abstracción)
+0

Uso default_charset() == "UTF-8". Esto es solo prueba. –

+0

@AlexandrErofeev: No estará claro cuando alguien está * leyendo * El código que codifica para usar. IMO es mucho mejor decirlo explícitamente. (Y si es solo como una prueba, elimine por completo todo el manejo de excepciones, y simplemente deje que todos los métodos arrojen 'IOException' - simplificará el código.) –

2

Cuando comprime datos GZIP, siempre obtiene datos binarios. Estos datos no se pueden convertir en cadenas ya que no hay datos de caracteres válidos (en cualquier codificación).

Así que su método compresa debe devolver una matriz de bytes y su método de descomprimir debe tener una matriz de bytes como parámetro.

Además, le recomiendo que utilice una codificación explícita cuando convierta la cadena en una matriz de bytes antes de la compresión y cuando vuelva a convertir los datos descomprimidos en una cadena.

+0

El hecho de que esto es solo una prueba. De hecho, desde el servidor, obtengo una cadena json que será la clave "zip". Que contiene los datos comprimidos. Puedo obtener el contenido de una clave como una cadena. Entonces necesito extraer esta información. –

+0

@AlexandrErofeev: Toda esta información debe haber incluido en la pregunta. Sospecho que el JSON incluye datos codificados en base64 ... así es como espero que represente datos binarios. –

+0

JSON no puede contener directamente datos binarios. Entonces, si la clave está codificada en GZIP, probablemente también esté codificada en Base64 para convertir los datos binarios en una cadena que JSON pueda contener. Probablemente deberías agregar una muestra JSON con la clave de tu pregunta. – Codo

0

Cuando comprime datos GZIP, siempre obtiene datos binarios. Estos datos no se pueden convertir en cadenas ya que no hay datos de caracteres válidos (en cualquier codificación).

Codo tiene razón, muchas gracias por aclararme. Estaba tratando de descomprimir una cadena (convertida a partir de los datos binarios). Lo que enmendé fue el uso de InflaterInputStream directamente en la secuencia de entrada devuelta por mi conexión http. (Mi aplicación estaba recuperando un JSON grande de cadenas)