No se puede extraer el archivo del archivo ZIP creado en Android (específico de dispositivo / OS)
Estoy creando un archivo en Android usando el código como este:
OutputStream os = new FileOutputStream(zipFile); ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(os)); try { zos.setLevel(8); byte[] buffer = new byte[32768]; for (VFile src : toPack) { ZipEntry entry = new ZipEntry(src.name); zos.putNextEntry(entry); src.pushToStream(zos, buffer); src.close(); zos.closeEntry(); } } finally { zos.close(); }
Encontré que hay solamente un método de la compresión disponible – DEFLATED
(hay solamente la alternativa STORED
disponible). Esto significa que el archivo siempre se comprime con un método.
- No se puede cargar el archivo TTF directamente desde un ZIP usando libzip y FreeType
- Osmdroid - cambiar la carpeta del mapa local
- Cómo leer un archivo directamente desde un archivo .zip sin extraerlo en android
- ¿Cómo puedo mantener la estructura de las carpetas cuando comprime en Java?
- Creación de un archivo zip con algunos archivos en SDCard
Si ejecuto este código en Android 2.3.4 – puedo descomprimir archivos en Windows usando 7Zip; Si ejecuto esto en Android 3 (o Samsung Galaxy Tab, no estoy seguro de quién lo hace mal) – 7Zip muestra la lista de archivos, pero no puede descomprimir archivo diciendo Unsupported método de compresión . Al mismo tiempo 7Zip muestra Deflate como un método de compresión en el archivo, lo que significa que puede tratarlo correctamente.
¿Alguien tiene este problema?
Gracias.
UDP: Encontró otro tema con un problema similar (puede no ser el mismo aunque).
- Android: descomprimir archivos zip codificados con contraseña
- Modificación del contenido de un archivo .aar de Android / Conversión a un formato .zip
- Android: ¿Obtener el número de archivos dentro de Zip?
- Archivo de expansión de Android
- Adición de Parse-1.8.0 a Android Studio 1.0.1 (O cualquier archivo .zip)
- Directorio de verificación de archivos zip de Java
- ¿Cómo descomprimir archivos zip AES-256 encriptados?
- Si no comprimo un archivo de texto sin formato en Android, ¿se comprimirá en el APK de todos modos?
La respuesta de @ user1269737 es correcta; casi. Pero sólo funciona para archivos de un solo archivo. A continuación se muestra un código que analiza todo el archivo.
/** * Replace wrong local file header byte * http://sourceforge.net/tracker/?func=detail&aid=3477810&group_id=14481&atid=114481 * Applies to Android API 9-13 * @param zip file * @throws IOException */ private static void fixInvalidZipFile(File zip) throws IOException { RandomAccessFile r = new RandomAccessFile(zip, "rw"); try { long eocd_offset = findEOCDRecord(r); if (eocd_offset > 0) { r.seek(eocd_offset + 16); // offset of first CDE in EOCD long cde_offset = readInt(r); // read offset of first Central Directory Entry long lfh_offset = 0; long fskip, dskip; while (true) { r.seek(cde_offset); if (readInt(r) != CDE_SIGNATURE) // got off sync! return; r.seek(cde_offset + 20); // compressed file size offset fskip = readInt(r); // fix the header // r.seek(lfh_offset + 7); short localFlagsHi = r.readByte(); // hi-order byte of local header flags (general purpose) r.seek(cde_offset + 9); short realFlagsHi = r.readByte(); // hi-order byte of central directory flags (general purpose) if (localFlagsHi != realFlagsHi) { // in latest versions this bug is fixed, so we're checking is bug exists. r.seek(lfh_offset + 7); r.write(realFlagsHi); } // calculate offset of next Central Directory Entry // r.seek(cde_offset + 28); // offset of variable CDE parts length in CDE dskip = 46; // length of fixed CDE part dskip += readShort(r); // file name dskip += readShort(r); // extra field dskip += readShort(r); // file comment cde_offset += dskip; if (cde_offset >= eocd_offset) // finished! break; // calculate offset of next Local File Header // r.seek(lfh_offset + 26); // offset of variable LFH parts length in LFH fskip += readShort(r); // file name fskip += readShort(r); // extra field fskip += 30; // length of fixed LFH part fskip += 16; // length of Data Descriptor (written after file data) lfh_offset += fskip; } } } finally { r.close(); } } //http://www.pkware.com/documents/casestudies/APPNOTE.TXT private static final int LFH_SIGNATURE = 0x04034b50; private static final int DD_SIGNATURE = 0x08074b50; private static final int CDE_SIGNATURE = 0x02014b50; private static final int EOCD_SIGNATURE = 0x06054b50; /** Find an offset of End Of Central Directory record in file */ private static long findEOCDRecord(RandomAccessFile f) throws IOException { long result = f.length() - 22; // 22 is minimal EOCD record length while (result > 0) { f.seek(result); if (readInt(f) == EOCD_SIGNATURE) return result; result--; } return -1; } /** Read a 4-byte integer from file converting endianness. */ private static int readInt(RandomAccessFile f) throws IOException { int result = 0; result |= f.read(); result |= (f.read() << 8); result |= (f.read() << 16); result |= (f.read() << 24); return result; } /** Read a 2-byte integer from file converting endianness. */ private static short readShort(RandomAccessFile f) throws IOException { short result = 0; result |= f.read(); result |= (f.read() << 8); return result; }
Necesidad de ser actualizado. Se corrige single-file-zip. Debe buscar la siguiente secuencia en el archivo zip {0, 0x08, 0x08, 0x08, 0} y reemplazarlo por {0, 0x08, 0x00, 0x08, 0}
/** * Replace wrong byte http://sourceforge.net/tracker/?func=detail&aid=3477810&group_id=14481&atid=114481 * @param zip file * @throws IOException */ private static void replaceWrongZipByte(File zip) throws IOException { RandomAccessFile r = new RandomAccessFile(zip, "rw"); int flag = Integer.parseInt("00001000", 2); //wrong byte r.seek(7); int realFlags = r.read(); if( (realFlags & flag) > 0) { // in latest versions this bug is fixed, so we're checking is bug exists. r.seek(7); flag = (~flag & 0xff); // removing only wrong bit, other bits remains the same. r.write(realFlags & flag); } r.close(); }
Versión actualizada :
El código siguiente elimina todos los bytes incorrectos en ZIP. KMPMatch.java fácil de encontrar en google
public static void replaceWrongBytesInZip(File zip) throws IOException { byte find[] = new byte[] { 0, 0x08, 0x08, 0x08, 0 }; int index; while( (index = indexOfBytesInFile(zip,find)) != -1) { replaceWrongZipByte(zip, index + 2); } } private static int indexOfBytesInFile(File file,byte find[]) throws IOException { byte fileContent[] = new byte[(int) file.length()]; FileInputStream fin = new FileInputStream(file); fin.read(fileContent); fin.close(); return KMPMatch.indexOf(fileContent, find); } /** * Replace wrong byte http://sourceforge.net/tracker/?func=detail&aid=3477810&group_id=14481&atid=114481 * @param zip file * @throws IOException */ private static void replaceWrongZipByte(File zip, int wrongByteIndex) throws IOException { RandomAccessFile r = new RandomAccessFile(zip, "rw"); int flag = Integer.parseInt("00001000", 2); r.seek(wrongByteIndex); int realFlags = r.read(); if( (realFlags & flag) > 0) { // in latest versions this bug is fixed, so we're checking is bug exists. r.seek(wrongByteIndex); flag = (~flag & 0xff); // removing only wrong bit, other bits remains the same. r.write(realFlags & flag); } r.close(); }