varios una empaquetar con comprimir como carpetas carpeta archivos archivo java zip war-files truezip

una - empaquetar archivos java



Anexar archivos a un archivo zip con Java (12)

Aquí está la versión Java 1.7 de la respuesta de Liam que usa try with resources y Apache Commons IO.

La salida se escribe en un nuevo archivo zip, pero se puede modificar fácilmente para escribir en el archivo original.

/** * Modifies, adds or deletes file(s) from a existing zip file. * * @param zipFile the original zip file * @param newZipFile the destination zip file * @param filesToAddOrOverwrite the names of the files to add or modify from the original file * @param filesToAddOrOverwriteInputStreams the input streams containing the content of the files * to add or modify from the original file * @param filesToDelete the names of the files to delete from the original file * @throws IOException if the new file could not be written */ public static void modifyZipFile(File zipFile, File newZipFile, String[] filesToAddOrOverwrite, InputStream[] filesToAddOrOverwriteInputStreams, String[] filesToDelete) throws IOException { try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(newZipFile))) { // add existing ZIP entry to output stream try (ZipInputStream zin = new ZipInputStream(new FileInputStream(zipFile))) { ZipEntry entry = null; while ((entry = zin.getNextEntry()) != null) { String name = entry.getName(); // check if the file should be deleted if (filesToDelete != null) { boolean ignoreFile = false; for (String fileToDelete : filesToDelete) { if (name.equalsIgnoreCase(fileToDelete)) { ignoreFile = true; break; } } if (ignoreFile) { continue; } } // check if the file should be kept as it is boolean keepFileUnchanged = true; if (filesToAddOrOverwrite != null) { for (String fileToAddOrOverwrite : filesToAddOrOverwrite) { if (name.equalsIgnoreCase(fileToAddOrOverwrite)) { keepFileUnchanged = false; } } } if (keepFileUnchanged) { // copy the file as it is out.putNextEntry(new ZipEntry(name)); IOUtils.copy(zin, out); } } } // add the modified or added files to the zip file if (filesToAddOrOverwrite != null) { for (int i = 0; i < filesToAddOrOverwrite.length; i++) { String fileToAddOrOverwrite = filesToAddOrOverwrite[i]; try (InputStream in = filesToAddOrOverwriteInputStreams[i]) { out.putNextEntry(new ZipEntry(fileToAddOrOverwrite)); IOUtils.copy(in, out); out.closeEntry(); } } } } }

Actualmente estoy extrayendo el contenido de un archivo war y luego agrego algunos archivos nuevos a la estructura del directorio y luego creo un nuevo archivo war.

Todo esto se hace programaticamente desde Java, pero me pregunto si no sería más eficiente copiar el archivo war y luego anexar los archivos, entonces no tendría que esperar mientras la guerra se expanda y luego tenga que ser comprimido de nuevo

Parece que no puedo encontrar una manera de hacer esto en la documentación o ejemplos en línea.

¿Alguien puede dar algunos consejos o punteros?

ACTUALIZAR:

TrueZip como se menciona en una de las respuestas parece ser una muy buena biblioteca de Java para agregar a un archivo zip (a pesar de otras respuestas que dicen que no es posible hacer esto).

¿Alguien tiene experiencia o comentarios sobre TrueZip o puede recomendar otras librerías similares?


Aquí hay ejemplos de la facilidad con la que se pueden TrueVFS archivos al zip existente usando TrueVFS :

// append a file to archive under different name TFile.cp(new File("existingFile.txt"), new TFile("archive.zip", "entry.txt")); // recusively append a dir to the root of archive TFile src = new TFile("dirPath", "dirName"); src.cp_r(new TFile("archive.zip", src.getName()));

TrueVFS, el sucesor de TrueZIP, utiliza las características de Java 7 NIO 2 bajo el capó cuando es apropiado, pero ofrece muchas más características como la compresión paralela asíncrona sin hilos.

Tenga en cuenta también que Java 7 ZipFileSystem por defecto es vulnerable a OutOfMemoryError en enormes entradas.


Como dice Cheeso, no hay forma de hacerlo. AFAIK los frontales con cremallera hacen exactamente lo mismo que tú internamente.

De todos modos, si le preocupa la velocidad de extracción / compresión de todo, es posible que desee probar la biblioteca SevenZipJBindings .

Cubrí esta biblioteca en mi blog algunos meses (lo siento por la auto-promoción). Solo a modo de ejemplo, extraer un archivo comprimido de 104MB con java.util.zip me llevó 12 segundos, mientras que el uso de esta biblioteca duró 4 segundos.

En ambos enlaces, puede encontrar ejemplos sobre cómo usarlo.

Espero eso ayude.


Como mencionaron otros, no es posible agregar contenido a un archivo zip (o war) existente. Sin embargo, es posible crear un nuevo archivo zip sobre la marcha sin escribir temporalmente el contenido extraído en el disco. Es difícil adivinar cuánto más rápido será, pero es lo más rápido que puede obtener (al menos hasta donde yo sé) con Java estándar. Como mencionó Carlos Tasada, SevenZipJBindings podría exprimir algunos segundos extra, pero trasladar este enfoque a SevenZipJBindings seguirá siendo más rápido que usar archivos temporales con la misma biblioteca.

Aquí hay un código que escribe el contenido de un archivo zip existente (war.zip) y agrega un archivo adicional (answer.txt) a un nuevo archivo zip (append.zip). Todo lo que necesita es Java 5 o posterior, no se necesitan bibliotecas adicionales.

import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; public class Main { // 4MB buffer private static final byte[] BUFFER = new byte[4096 * 1024]; /** * copy input to output stream - available in several StreamUtils or Streams classes */ public static void copy(InputStream input, OutputStream output) throws IOException { int bytesRead; while ((bytesRead = input.read(BUFFER))!= -1) { output.write(BUFFER, 0, bytesRead); } } public static void main(String[] args) throws Exception { // read war.zip and write to append.zip ZipFile war = new ZipFile("war.zip"); ZipOutputStream append = new ZipOutputStream(new FileOutputStream("append.zip")); // first, copy contents from existing war Enumeration<? extends ZipEntry> entries = war.entries(); while (entries.hasMoreElements()) { ZipEntry e = entries.nextElement(); System.out.println("copy: " + e.getName()); append.putNextEntry(e); if (!e.isDirectory()) { copy(war.getInputStream(e), append); } append.closeEntry(); } // now append some extra content ZipEntry e = new ZipEntry("answer.txt"); System.out.println("append: " + e.getName()); append.putNextEntry(e); append.write("42/n".getBytes()); append.closeEntry(); // close war.close(); append.close(); } }


En Java 7 tenemos Zip File System que permite agregar y cambiar archivos en zip (jar, war) sin reempaquetado manual.

Podemos escribir directamente en archivos dentro de archivos zip como en el siguiente ejemplo.

Map<String, String> env = new HashMap<>(); env.put("create", "true"); Path path = Paths.get("test.zip"); URI uri = URI.create("jar:" + path.toUri()); try (FileSystem fs = FileSystems.newFileSystem(uri, env)) { Path nf = fs.getPath("new.txt"); try (Writer writer = Files.newBufferedWriter(nf, StandardCharsets.UTF_8, StandardOpenOption.CREATE)) { writer.write("hello"); } }


En algún momento tuve un requisito similar, pero era para leer y escribir archivos comprimidos (el formato .war debería ser similar). Intenté hacerlo con las secuencias Java Zip existentes, pero encontré la parte de escritura engorrosa, especialmente cuando los directorios estaban involucrados.

Te recomendaré que pruebes la TrueZIP (fuente abierta - licencia de estilo apache) que expone cualquier archivo como un sistema de archivos virtual en el que puedes leer y escribir como un sistema de archivos normal. Funcionó como un encanto para mí y simplificó enormemente mi desarrollo.


No sé de una biblioteca Java que haga lo que describes. Pero lo que describes es práctico. Puedes hacerlo en .NET, usando DotNetZip .

Michael Krauklis tiene razón en que no se puede simplemente "anexar" datos a un archivo de guerra o archivo zip, pero no se debe a que haya una indicación de "fin de archivo", estrictamente hablando, en un archivo war. Es porque el formato war (zip) incluye un directorio, que normalmente está presente al final del archivo, que contiene metadatos para las diversas entradas en el archivo war. Añadir Naively a un archivo de guerra no genera ninguna actualización en el directorio, por lo que solo tiene un archivo de guerra con basura adjunta.

Lo que es necesario es una clase inteligente que entienda el formato, y puede leer + actualizar un archivo de guerra o archivo zip, incluido el directorio según corresponda. DotNetZip hace esto, sin descomprimir / recomprimir las entradas sin cambios, tal como lo describió o deseó.


Otra solución más: puede encontrar que el siguiente código también es útil en otras situaciones. He usado la hormiga de esta manera para compilar directorios de Java, generar archivos jar, actualizar archivos zip, ...

public static void antUpdateZip(String zipFilePath, String libsToAddDir) { Project p = new Project(); p.init(); Target target = new Target(); target.setName("zip"); Zip task = new Zip(); task.init(); task.setDestFile(new File(zipFilePath)); ZipFileSet zipFileSet = new ZipFileSet(); zipFileSet.setPrefix("WEB-INF/lib"); zipFileSet.setDir(new File(libsToAddDir)); task.addFileset(zipFileSet); task.setUpdate(true); task.setProject(p); task.init(); target.addTask(task); target.setProject(p); p.addTarget(target); DefaultLogger consoleLogger = new DefaultLogger(); consoleLogger.setErrorPrintStream(System.err); consoleLogger.setOutputPrintStream(System.out); consoleLogger.setMessageOutputLevel(Project.MSG_DEBUG); p.addBuildListener(consoleLogger); try { // p.fireBuildStarted(); // ProjectHelper helper = ProjectHelper.getProjectHelper(); // p.addReference("ant.projectHelper", helper); // helper.parse(p, buildFile); p.executeTarget(target.getName()); // p.fireBuildFinished(null); } catch (BuildException e) { p.fireBuildFinished(e); throw new AssertionError(e); } }


Podrías usar este fragmento de código que escribí

public static void addFilesToZip(File source, File[] files) { try { File tmpZip = File.createTempFile(source.getName(), null); tmpZip.delete(); if(!source.renameTo(tmpZip)) { throw new Exception("Could not make temp file (" + source.getName() + ")"); } byte[] buffer = new byte[1024]; ZipInputStream zin = new ZipInputStream(new FileInputStream(tmpZip)); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(source)); for(int i = 0; i < files.length; i++) { InputStream in = new FileInputStream(files[i]); out.putNextEntry(new ZipEntry(files[i].getName())); for(int read = in.read(buffer); read > -1; read = in.read(buffer)) { out.write(buffer, 0, read); } out.closeEntry(); in.close(); } for(ZipEntry ze = zin.getNextEntry(); ze != null; ze = zin.getNextEntry()) { out.putNextEntry(ze); for(int read = zin.read(buffer); read > -1; read = zin.read(buffer)) { out.write(buffer, 0, read); } out.closeEntry(); } out.close(); tmpZip.delete(); } catch(Exception e) { e.printStackTrace(); } }


Vea este informe de error .

Usar el modo de agregar en cualquier tipo de datos estructurados, como archivos zip o tar no es algo que realmente pueda funcionar. Estos formatos de archivo tienen una indicación intrínseca de "fin de archivo" integrada en el formato de datos.

Si realmente desea omitir el paso intermedio de no-waring / re-waring, puede leer el archivo war file, obtener todas las entradas zip y luego escribir en un nuevo archivo war agregando las nuevas entradas que desea agregar. No es perfecto, pero al menos es una solución más automatizada.


este es un código simple para obtener una respuesta con el uso de servlet y enviar una respuesta

myZipPath = bla bla... byte[] buf = new byte[8192]; String zipName = "myZip.zip"; String zipPath = myzippath+ File.separator+"pdf" + File.separator+ zipName; File pdfFile = new File("myPdf.pdf"); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipPath)); ZipEntry zipEntry = new ZipEntry(pdfFile.getName()); out.putNextEntry(zipEntry); InputStream in = new FileInputStream(pdfFile); int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } out.closeEntry(); in.close(); out.close(); FileInputStream fis = new FileInputStream(zipPath); response.setContentType("application/zip"); response.addHeader("content-disposition", "attachment;filename=" + zipName); OutputStream os = response.getOutputStream(); int length = is.read(buffer); while (length != -1) { os.write(buffer, 0, length); length = is.read(buffer); }


esto funciona al 100%, si no quieres usar libs adicionales ... 1) primero, la clase que anexa archivos al zip.

import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class AddZip { public void AddZip() { } public void addToZipFile(ZipOutputStream zos, String nombreFileAnadir, String nombreDentroZip) { FileInputStream fis = null; try { if (!new File(nombreFileAnadir).exists()) {//NO EXISTE System.out.println(" No existe el archivo : " + nombreFileAnadir);return; } File file = new File(nombreFileAnadir); System.out.println(" Generando el archivo ''" + nombreFileAnadir + "'' al ZIP "); fis = new FileInputStream(file); ZipEntry zipEntry = new ZipEntry(nombreDentroZip); zos.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while ((length = fis.read(bytes)) >= 0) {zos.write(bytes, 0, length);} zos.closeEntry(); fis.close(); } catch (FileNotFoundException ex ) { Logger.getLogger(AddZip.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(AddZip.class.getName()).log(Level.SEVERE, null, ex); } } }

2) puedes llamarlo en tu controlador ...

//in the top try { fos = new FileOutputStream(rutaZip); zos = new ZipOutputStream(fos); } catch (FileNotFoundException ex) { Logger.getLogger(UtilZip.class.getName()).log(Level.SEVERE, null, ex); } ... //inside your method addZip.addToZipFile(zos, pathFolderFileSystemHD() + itemFoto.getNombre(), "foto/" + itemFoto.getNombre());