Borre archivos de un archivo ZIP sin descomprimir en Java o quizás Python

Elimine archivos de un archivo ZIP sin descomprimir usando Java (preferido) o Python

Hola,

Trabajo con archivos ZIP grandes que contienen muchos cientos de archivos de texto altamente comprimidos. Cuando descomprimo el archivo ZIP, puede tomar un tiempo y consumir fácilmente hasta 20 GB de espacio en disco. Me gustaría eliminar ciertos archivos de estos archivos ZIP sin tener que descomprimir y recomprimir solo los archivos que deseo.

Por supuesto, es ciertamente posible hacerlo a largo plazo, pero muy ineficiente.

Preferiría hacer esto en Java, pero consideraré Python

He encontrado esto en la web

Solución limpia con solo una biblioteca estándar, pero no estoy seguro de si está incluido en el SDK de Android, que se encontrará.

import java.util.*; import java.net.URI; import java.nio.file.Path; import java.nio.file.*; import java.nio.file.StandardCopyOption; public class ZPFSDelete { public static void main(String [] args) throws Exception { /* Define ZIP File System Properies in HashMap */ Map zip_properties = new HashMap<>(); /* We want to read an existing ZIP File, so we set this to False */ zip_properties.put("create", "false"); /* Specify the path to the ZIP File that you want to read as a File System */ URI zip_disk = URI.create("jar:file:/my_zip_file.zip"); /* Create ZIP file System */ try (FileSystem zipfs = FileSystems.newFileSystem(zip_disk, zip_properties)) { /* Get the Path inside ZIP File to delete the ZIP Entry */ Path pathInZipfile = zipfs.getPath("source.sql"); System.out.println("About to delete an entry from ZIP File" + pathInZipfile.toUri() ); /* Execute Delete */ Files.delete(pathInZipfile); System.out.println("File successfully deleted"); } } } 

No tengo un código para hacer esto, pero la idea básica es simple y debería traducirse a casi cualquier idioma de la misma manera. El diseño del archivo ZIP es solo una serie de bloques que representan archivos (un encabezado seguido de los datos comprimidos), terminados con un directorio central que solo contiene todos los metadatos. Aquí está el proceso:

  1. Escanee hacia adelante en el archivo hasta que encuentre el primer archivo que desea eliminar.
  2. Escanee hacia adelante en el archivo hasta que encuentre el primer archivo que no desea eliminar o presione el directorio central.
  3. Escanee hacia adelante en el archivo hasta que encuentre el primer archivo que desea eliminar o presione el directorio central.
  4. Copie todos los datos que encontró en el paso 3 de nuevo en los datos que omitió en el paso 2 hasta que encuentre otro archivo que desee eliminar o toque el directorio central.
  5. Vaya al paso 2 a menos que haya golpeado el directorio central.
  6. Copie el directorio central donde siempre dejó de copiar, omitiendo las entradas de los archivos eliminados y cambiando las compensaciones para reflejar cuánto movió cada archivo.

Consulte http://en.wikipedia.org/wiki/ZIP_%28file_format%29 para obtener todos los detalles sobre las estructuras de los archivos ZIP.

Como sugiere bestsss, es posible que desee realizar la copia en otro archivo, para evitar la pérdida de datos en caso de falla.

Ok, creo que encontré una solución potencial de http://www.javaer.org. Definitivamente elimina archivos dentro del zip y no creo que esté descomprimiendo nada. Aquí está el código:

 public static void deleteZipEntry(File zipFile, String[] files) throws IOException { // get a temp file File tempFile = File.createTempFile(zipFile.getName(), null); // delete it, otherwise you cannot rename your existing zip to it. tempFile.delete(); tempFile.deleteOnExit(); boolean renameOk=zipFile.renameTo(tempFile); if (!renameOk) { throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath()); } byte[] buf = new byte[1024]; ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile)); ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipFile)); ZipEntry entry = zin.getNextEntry(); while (entry != null) { String name = entry.getName(); boolean toBeDeleted = false; for (String f : files) { if (f.equals(name)) { toBeDeleted = true; break; } } if (!toBeDeleted) { // Add ZIP entry to output stream. zout.putNextEntry(new ZipEntry(name)); // Transfer bytes from the ZIP file to the output file int len; while ((len = zin.read(buf)) > 0) { zout.write(buf, 0, len); } } entry = zin.getNextEntry(); } // Close the streams zin.close(); // Compress the files // Complete the ZIP file zout.close(); tempFile.delete(); 

}

Sí, es posible que JAVA utilice una biblioteca llamada TRUEZIP .

TrueZIP es un sistema de archivos virtuales (VFS) basado en Java que permite que las aplicaciones cliente realicen operaciones CRUD (Crear, Leer, Actualizar, Eliminar) en archivos comprimidos como si fueran directorios virtuales, incluso con archivos archivados nesteds en entornos multiproceso.

Consulte el siguiente enlace para obtener más información https://truezip.java.net/

Esto puede ser viejo, pero aquí hay una manera. Y funciona porque lo uso constantemente y funciona bien.

 public boolean deleteFile(String zip_dir, String subfile){ delete(new File(zipdir, subfile)); } private void delete(File file) { if(file == null || !file.exists()) return; if(file.isFile()) { file.delete(); return; } File children[] = file.listFiles(); for(int i = 0; i < children.length; i++) { File child = children[i]; if(child.isFile()) child.delete(); else delete(child); } file.delete(); }