ZIP and TAR fomats (and the old AR format) allow file append without a full rewrite. However:

  • The Java archive classes DO NOT support this mode of operation.
  • File append is likely to result in multiple copies of a file in the archive if you append an existing file.
  • The ZIP and AR formats have a directory that needs to be rewritten following a file append operation. The standard utilities take precautions when rewriting the directory, but it is possible in theory that you may end up with an archive with a missing or corrupted directory if the append fails.

The ZIP file format was designed to allow appends without a total re-write and is ubiquitous, even on Unix.

http://stackoverflow.com/questions/2993847/append-files-to-an-archive-without-reading-rewriting-the-whole-archive/2993964#2993964

I am using java.util.zip to add some configuration resources into a jar file. when I call addFileToZip() method it overwrites the jar completely, instead of adding the file to the jar. Why I need to write the config to the jar is completely irrelevant. and I do not wish to use any external API's.

EDIT: The jar is not running in the VM and org.cfg.resource is the package I'm trying to save the file to, the file is a standard text document and the jar being edited contains the proper information before this method is used.

My code:

  1. public void addFileToZip(File fileToAdd, File zipFile)
  2. {
  3. ZipOutputStream zos = null;
  4. FileInputStream fis = null;
  5. ZipEntry ze = null;
  6. byte[] buffer = null;
  7. int len;
  8.  
  9. try {
  10. zos = new ZipOutputStream(new FileOutputStream(zipFile));
  11. } catch (FileNotFoundException e) {
  12. }
  13.  
  14. ze = new ZipEntry("org" + File.separator + "cfg" +
  15. File.separator + "resource" + File.separator + fileToAdd.getName());
  16. try {
  17. zos.putNextEntry(ze);
  18.  
  19. fis = new FileInputStream(fileToAdd);
  20. buffer = new byte[(int) fileToAdd.length()];
  21.  
  22. while((len = fis.read(buffer)) > 0)
  23. {
  24. zos.write(buffer, 0, len);
  25. }
  26. } catch (IOException e) {
  27. }
  28. try {
  29. zos.flush();
  30. zos.close();
  31. fis.close();
  32. } catch (IOException e) {
  33. }
  34. }

The code you showed overrides a file no matter if it would be a zip file or not. ZipOutputStream does not care about existing data. Neither any stream oriented API does.

I would recommend

  1. Create new file using ZipOutputStream.

  2. Open existing with ZipInputStream

  3. Copy existing entries to new file.

  4. Add new entries.

  5. Replace old file with a new one.


Hopefully in Java 7 we got Zip File System that will save you a lot of work.

We can directly write to files inside zip files

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

http://stackoverflow.com/questions/17500856/java-util-zip-adding-a-new-file-overwrites-entire-jar?lq=1

As others mentioned, it's not possible to append content to an existing zip (or war). However, it's possible to create a new zip on the fly without temporarily writing extracted content to disk. It's hard to guess how much faster this will be, but it's the fastest you can get (at least as far as I know) with standard Java. As mentioned by Carlos Tasada, SevenZipJBindings might squeeze out you some extra seconds, but porting this approach to SevenZipJBindings will still be faster than using temporary files with the same library.

Here's some code that writes the contents of an existing zip (war.zip) and appends an extra file (answer.txt) to a new zip (append.zip). All it takes is Java 5 or later, no extra libraries needed.

  1. public static void addFilesToExistingZip(File zipFile,
  2. File[] files) throws IOException {
  3. // get a temp file
  4. File tempFile = File.createTempFile(zipFile.getName(), null);
  5. // delete it, otherwise you cannot rename your existing zip to it.
  6. tempFile.delete();
  7.  
  8. boolean renameOk=zipFile.renameTo(tempFile);
  9. if (!renameOk)
  10. {
  11. throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
  12. }
  13. byte[] buf = new byte[1024];
  14.  
  15. ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
  16. ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
  17.  
  18. ZipEntry entry = zin.getNextEntry();
  19. while (entry != null) {
  20. String name = entry.getName();
  21. boolean notInFiles = true;
  22. for (File f : files) {
  23. if (f.getName().equals(name)) {
  24. notInFiles = false;
  25. break;
  26. }
  27. }
  28. if (notInFiles) {
  29. // Add ZIP entry to output stream.
  30. out.putNextEntry(new ZipEntry(name));
  31. // Transfer bytes from the ZIP file to the output file
  32. int len;
  33. while ((len = zin.read(buf)) > 0) {
  34. out.write(buf, 0, len);
  35. }
  36. }
  37. entry = zin.getNextEntry();
  38. }
  39. // Close the streams
  40. zin.close();
  41. // Compress the files
  42. for (int i = 0; i < files.length; i++) {
  43. InputStream in = new FileInputStream(files[i]);
  44. // Add ZIP entry to output stream.
  45. out.putNextEntry(new ZipEntry(files[i].getName()));
  46. // Transfer bytes from the file to the ZIP file
  47. int len;
  48. while ((len = in.read(buf)) > 0) {
  49. out.write(buf, 0, len);
  50. }
  51. // Complete the entry
  52. out.closeEntry();
  53. in.close();
  54. }
  55. // Complete the ZIP file
  56. out.close();
  57. tempFile.delete();
  58. }
  1. public static void addFilesToZip(File source, File[] files)
  2. {
  3. try
  4. {
  5.  
  6. File tmpZip = File.createTempFile(source.getName(), null);
  7. tmpZip.delete();
  8. if(!source.renameTo(tmpZip))
  9. {
  10. throw new Exception("Could not make temp file (" + source.getName() + ")");
  11. }
  12. byte[] buffer = new byte[1024];
  13. ZipInputStream zin = new ZipInputStream(new FileInputStream(tmpZip));
  14. ZipOutputStream out = new ZipOutputStream(new FileOutputStream(source));
  15.  
  16. for(int i = 0; i < files.length; i++)
  17. {
  18. InputStream in = new FileInputStream(files[i]);
  19. out.putNextEntry(new ZipEntry(files[i].getName()));
  20. for(int read = in.read(buffer); read > -1; read = in.read(buffer))
  21. {
  22. out.write(buffer, 0, read);
  23. }
  24. out.closeEntry();
  25. in.close();
  26. }
  27.  
  28. for(ZipEntry ze = zin.getNextEntry(); ze != null; ze = zin.getNextEntry())
  29. {
  30. out.putNextEntry(ze);
  31. for(int read = zin.read(buffer); read > -1; read = zin.read(buffer))
  32. {
  33. out.write(buffer, 0, read);
  34. }
  35. out.closeEntry();
  36. }
  37.  
  38. out.close();
  39. tmpZip.delete();
  40. }
  41. catch(Exception e)
  42. {
  43. e.printStackTrace();
  44. }
  45. }

you cannot simply "append" data to a war file or zip file, but it is not because there is an "end of file" indication, strictly speaking, in a war file. It is because the war (zip) format includes a directory, which is normally present at the end of the file, that contains metadata for the various entries in the war file. Naively appending to a war file results in no update to the directory, and so you just have a war file with junk appended to it.

http://stackoverflow.com/questions/2223434/appending-files-to-a-zip-file-with-java

How can I add entries to an existing zip file in Java

You could use zipFile.entries() to get an enumeration of all of the ZipEntry objects in the existing file,
loop through them and add them all to the ZipOutputStream, and then add your new entries in addition.

The function renames the existing zip file to a temporary file and then adds all entries in the existing zip along with the new files, excluding the zip entries that have the same name as one of the new files.

  1. public static void addFilesToExistingZip(File zipFile,
  2. File[] files) throws IOException {
  3. // get a temp file
  4. File tempFile = File.createTempFile(zipFile.getName(), null);
  5. // delete it, otherwise you cannot rename your existing zip to it.
  6. tempFile.delete();
  7.  
  8. boolean renameOk=zipFile.renameTo(tempFile);
  9. if (!renameOk)
  10. {
  11. throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
  12. }
  13. byte[] buf = new byte[1024];
  14.  
  15. ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
  16. ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
  17.  
  18. ZipEntry entry = zin.getNextEntry();
  19. while (entry != null) {
  20. String name = entry.getName();
  21. boolean notInFiles = true;
  22. for (File f : files) {
  23. if (f.getName().equals(name)) {
  24. notInFiles = false;
  25. break;
  26. }
  27. }
  28. if (notInFiles) {
  29. // Add ZIP entry to output stream.
  30. out.putNextEntry(new ZipEntry(name));
  31. // Transfer bytes from the ZIP file to the output file
  32. int len;
  33. while ((len = zin.read(buf)) > 0) {
  34. out.write(buf, 0, len);
  35. }
  36. }
  37. entry = zin.getNextEntry();
  38. }
  39. // Close the streams
  40. zin.close();
  41. // Compress the files
  42. for (int i = 0; i < files.length; i++) {
  43. InputStream in = new FileInputStream(files[i]);
  44. // Add ZIP entry to output stream.
  45. out.putNextEntry(new ZipEntry(files[i].getName()));
  46. // Transfer bytes from the file to the ZIP file
  47. int len;
  48. while ((len = in.read(buf)) > 0) {
  49. out.write(buf, 0, len);
  50. }
  51. // Complete the entry
  52. out.closeEntry();
  53. in.close();
  54. }
  55. // Complete the ZIP file
  56. out.close();
  57. tempFile.delete();
  58. }

http://stackoverflow.com/questions/3048669/how-can-i-add-entries-to-an-existing-zip-file-in-java?lq=1

Java.util.zip adding a new file overwrites entire jar?(转)的更多相关文章

  1. java.util.zip.ZipException:ZIP file must have at least one entry

    1.错误描述 java.util.zip.ZipException:ZIP file must have at least one entry 2.错误原因 由于在导出文件时,要将导出的文件压缩到压缩 ...

  2. Tomcat启动报错:org.apache.catalina.LifecycleException: Failed to start component...java.util.zip.ZipException: error in opening zip file

    1.项目环境 IntelliJ IDEA2018.1.6 apache-tomcat-8.0.53 基于springboot开发的项目 maven3.5.3 2.出现问题 从svn同步下项目 启动to ...

  3. [java ] java.util.zip.ZipException: error in opening zip file

    严重: Failed to processes JAR found at URL [jar:file:/D:/tools/apache-tomcat-7.0.64_2/webapps/bbs/WEB- ...

  4. 【POI】解析xls报错:java.util.zip.ZipException: error in opening zip file

    今天使用POI解析XLS,报错如下: Servlet.service() for servlet [rest] in context with path [/cetBrand] threw excep ...

  5. Caused by: java.util.zip.ZipException: zip file is empty

    1.问题描述:mybranch分支代码和master分支的代码一模一样,mybranch代码部署到服务器上没有任何问题,而master代码部署到服务器上运行不起来. 2.解决办法: (1)登陆服务器启 ...

  6. java.util.zip - Recreating directory structure(转)

    include my own version for your reference. We use this one to zip up photos to download so it works ...

  7. [Java 基础] 使用java.util.zip包压缩和解压缩文件

    reference :  http://www.open-open.com/lib/view/open1381641653833.html Java API中的import java.util.zip ...

  8. java.util.zip压缩打包文件总结二: ZIP解压技术

    一.简述 解压技术和压缩技术正好相反,解压技术要用到的类:由ZipInputStream通过read方法对数据解压,同时需要通过CheckedInputStream设置冗余校验码,如: Checked ...

  9. java.util.zip压缩打包文件总结一:压缩文件及文件下面的文件夹

    一.简述 zip用于压缩和解压文件.使用到的类有:ZipEntry  ZipOutputStream 二.具体实现代码 package com.joyplus.test; import java.io ...

随机推荐

  1. 关于 Swift

    摘自:http://numbbbbb.gitbooks.io/-the-swift-programming-language-/chapter1/01_swift.html Swift 是一种新的编程 ...

  2. MinGW开发工具的安装

    MinGW是Minimalist GNU for Windows的缩写,是把linux下的GNU开发工具包移植到windows的项目之一.和Cygwin不一样的是,MinGW不提供linux的posi ...

  3. 初探 插头DP

    因为这题,气得我火冒三丈! 这数据是不是有问题啊!我用cin代替scanf后居然就AC了(本来一直卡在Test 18)!导致我调(对)试(排)了一个小时!! UPD:后来细细想想,会不会是因为scan ...

  4. 蛋疼的Apple IOS Push通知协议

    简单介绍 Apple Push通知机制事实上非常easy,就是Apple的APNsserver做为中间人,把消息推送到相应的设备上. 一张来自Apple文档的图: 当然,示意图看起来简单,可是另一些实 ...

  5. asp.net 生成xml文件 与 asp生成xml文件

    一.asp.net 生成xml文件 webservice方式,调用接口: public XmlDocument List() { XmlDocument doc = new XmlDocument() ...

  6. 基于visual Studio2013解决C语言竞赛题之1031猜数

          题目 解决代码及点评 /* 31. 猜号码∶由随机函数产生一个1至1000之间的整数,让人猜之. 计算机仅回答人猜的数大.小还是相等,当人猜对时, 由计算机打印出人 ...

  7. Stack栈的三种含义

    理解stack栈对于理解程序的执行至关重要.easy混淆的是,这个词事实上有三种含义,适用于不同的场合,必须加以区分. 含义一:数据结构 stack的第一种含义是一组数据的存放方式,特点为LIFO,即 ...

  8. CheckBox in ListView

    CheckBox in ListView Listview 在android中是经常用的组件,一些特殊情况下,系统提供的list view item 不够用, 不能满足需求,那么就需要自定义listV ...

  9. 初入Android--Activate生命周期

    Activate的主要生命周期 (注意:这只是主要的生命周期,而不是完整的生命周期方法,其中的两个周期之间可能还执行了其他的一些方法) 每个时刻在屏幕上的状态 进入onCreate方法:Activat ...

  10. Qt之日志输出文件

    在Qt开发过程当中经常使用qDebug等一些输出来调试程序,但是到了正式发布的时候,都会被注释或者删除,采用日志输出来代替.     做过项目的童鞋可能都使用过日志功能,以便有异常错误能够快速跟踪.定 ...