¿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:
- Comprimir una cadena usando GZIPOutputStream
- ¿Qué encabezado se debe utilizar para enviar GZIP comprimido JSON de Android Client a Server?
- GZIPInputStream falla con IOException en Android 2.3, pero funciona bien en todas las versiones anteriores?
- ¿Cómo crear un archivo .Gzip en android y también cifrar y descifrar ese archivo?
- Uso de archivos SVGZ sin servidor. (IOS local / 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?
- Cómo Retrofit con OKHttp utilizar datos de caché cuando está fuera de línea
- Cómo comprimir JSON con gzip en Rails para Android?
- La lectura de cadena gzip en sqlite3 base de datos (python escribir, Java Android leer)
- OkHttp cuerpo del poste del gzip
- ¿Cómo puedo Zip y descomprimir una cadena usando GZIPOutputStream que es compatible con .Net?
- Gestionar automáticamente las respuestas http de gzip en Android
- Android post gzip
- ¿Cómo puedo escribir una declaración posterior a una HttpUrlConnection que está comprimida?
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).
- ¿Cómo puedo asegurarme de que Android Beam no inicie una nueva instancia de mi actividad "singleTop"?
- Aplicación de Proguard a una aplicación existente en Google Play