¿Por qué el resultado del algoritmo GZip no es el mismo en Android y .Net?

¿Por qué el resultado del algoritmo GZip no es el mismo en Android y .Net?

Mi código en android:

public static String compressString(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 Base64.encode(b1); } 

Mi código en el .Net WebService:

  public static string compressString(string text) { byte[] buffer = Encoding.UTF8.GetBytes(text); MemoryStream ms = new MemoryStream(); using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true)) { zip.Write(buffer, 0, buffer.Length); } ms.Position = 0; MemoryStream outStream = new MemoryStream(); byte[] compressed = new byte[ms.Length]; ms.Read(compressed, 0, compressed.Length); byte[] gzBuffer = new byte[compressed.Length + 4]; System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length); System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4); return Convert.ToBase64String(gzBuffer); } 

En android:

 compressString("hello"); -> "H4sIAAAAAAAAAMtIzcnJBwCGphA2BQAAAA==" 

En la red:

 compressString("hello"); -> "BQAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyLmeVlW/w+GphA2BQAAAA==" 

Es interesante que cuando uso el método Decompress en android para descomprimir el resultado del método compressString .Net, devuelve la cadena original correctamente pero consigo error cuando descomprimo el resultado del método android compressedString .

Android método Decompress:

  public static String Decompress(String zipText) throws IOException { int size = 0; byte[] gzipBuff = Base64.decode(zipText); ByteArrayInputStream memstream = new ByteArrayInputStream(gzipBuff, 4, gzipBuff.length - 4); GZIPInputStream gzin = new GZIPInputStream(memstream); final int buffSize = 8192; byte[] tempBuffer = new byte[buffSize]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((size = gzin.read(tempBuffer, 0, buffSize)) != -1) { baos.write(tempBuffer, 0, size); } byte[] buffer = baos.toByteArray(); baos.close(); return new String(buffer, "UTF-8"); } 

Creo que hay un error en el método compressString de Android. ¿Puede alguien ayudarme?

En la versión para Android, debe cerrar bos después de cerrar gz .

Además, esta línea en compressString puede darle problemas:

 byte b[] = str.getBytes(); 

Eso convertirá los caracteres en bytes usando la codificación por defecto en el dispositivo, lo cual casi seguro no es UTF-8. La versión .NET, por otro lado, está utilizando UTF8. En Android, prueba esto:

 byte b[] = str.getBytes("UTF-8"); 

EDIT: Al seguir viendo su código, le sugiero que lo reescriba así:

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

Los cambios son: use UTF-8 para codificar caracteres; Utilice el tamaño de búfer interno predeterminado para el GZIPOutputStream; Llama a gz.close() antes de llamar a bos.close() (este último probablemente ni siquiera es necesario); Y llame a gz.finish() antes de llamar a gz.close() .

EDIT 2:

Vale, debería haberlo comprendido antes de lo que está pasando. La clase GZIPOutputStream es, en mi opinión, un diseño estúpido. No tiene manera de definir la compresión que desea y la compresión predeterminada se establece en ninguno. Necesita subclases y sobreescribir la compresión predeterminada. La manera más fácil es hacer esto:

 GZIPOutputStream gz = new GZIPOutputStream(bos) { { def.setLevel(Deflater.BEST_COMPRESSION); } }; 

Esto restablecerá el deflactor interno que GZIP usa para dar la mejor compresión. (Por cierto, en caso de que no esté familiarizado con él, la sintaxis que estoy usando aquí se llama un bloque de inicializador de instancia .)

De acuerdo con esta respuesta , tengo 4 métodos. Android y .net comprimen y descomprimen métodos. Estos métodos son compatibles entre sí excepto en un caso.

La principal diferencia es que su código .NET pone la longitud de los datos comprimidos en los primeros cuatro bytes de los datos binarios. Los códigos Java no lo hacen. Falta el campo de longitud.

Cuando la descomprime, sin embargo espera la longitud en los primeros cuatro bytes e inicia la descompresión GZIP en la posición 4 (saltando los primeros cuatro bytes).

  • GZIPInputStream lanza formato desconocido (número mágico 213c)
  • Android: la comunicación HTTP debe utilizar "Accept-Encoding: gzip"
  • Google Cloud Endpoints EOFException
  • HttpURLConnection no descomprimir Gzip
  • GZip en android
  • Retrofit + OkHttp + GZIP-ed JSON
  • Compresión de GZIP a una matriz de bytes
  • Android: lee un archivo GZIP en la carpeta ASSETS
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.