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:

public void addFileToZip(File fileToAdd, File zipFile)
{
ZipOutputStream zos = null;
FileInputStream fis = null;
ZipEntry ze = null;
byte[] buffer = null;
int len; try {
zos = new ZipOutputStream(new FileOutputStream(zipFile));
} catch (FileNotFoundException e) {
} ze = new ZipEntry("org" + File.separator + "cfg" +
File.separator + "resource" + File.separator + fileToAdd.getName());
try {
zos.putNextEntry(ze); fis = new FileInputStream(fileToAdd);
buffer = new byte[(int) fileToAdd.length()]; while((len = fis.read(buffer)) > 0)
{
zos.write(buffer, 0, len);
}
} catch (IOException e) {
}
try {
zos.flush();
zos.close();
fis.close();
} catch (IOException e) {
}
}

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

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");
}
}

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.

public static void addFilesToExistingZip(File zipFile,
File[] 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(); 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 out = new ZipOutputStream(new FileOutputStream(zipFile)); ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean notInFiles = true;
for (File f : files) {
if (f.getName().equals(name)) {
notInFiles = false;
break;
}
}
if (notInFiles) {
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
// Compress the files
for (int i = 0; i < files.length; i++) {
InputStream in = new FileInputStream(files[i]);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(files[i].getName()));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
tempFile.delete();
}
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();
}
}

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.

public static void addFilesToExistingZip(File zipFile,
File[] 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(); 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 out = new ZipOutputStream(new FileOutputStream(zipFile)); ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean notInFiles = true;
for (File f : files) {
if (f.getName().equals(name)) {
notInFiles = false;
break;
}
}
if (notInFiles) {
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
// Compress the files
for (int i = 0; i < files.length; i++) {
InputStream in = new FileInputStream(files[i]);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(files[i].getName()));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
tempFile.delete();
}

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. Ext.net中常用的三种交互方式

    http://www.ext.net.cn/forum.php?mod=viewthread&tid=10433

  2. Python 第八篇:异常处理、Socket语法、SocketServer实现多并发、进程和线程、线程锁、GIL、Event、信号量、进程间通讯

    本节内容: 异常处理.Socket语法.SocketServer实现多并发.进程和线程.线程锁.GIL.Event.信号量.进程间通讯.生产者消费者模型.队列Queue.multiprocess实例 ...

  3. 实战 iTextSharp

    原文 实战 iTextSharp iTextSharp 是用来生成  PDF 的一个组件,在 1998 年夏天的时候,Bruno Lowagie ,iText 的创作者,参与了学校的一个项目,当时使用 ...

  4. Java基础:多态(重载和重写)

    转载请注明出处:jiq•钦's technical Blog (1)域与静态方法 记住"仅仅有普通方法的调用是多态的". 而域和静态方法不是:对于域的訪问.在编译期间就已经进行解析 ...

  5. 基于MapReduce的HBase开发

    在伪分布式模式和全分布式模式下 HBase 是架构在 HDFS 上的,因此完全可以将MapReduce 编程框架和 HBase 结合起来使用.也就是说,将 HBase 作为底层“存储结构”, MapR ...

  6. Cocos2d-x 3.2 大富翁游戏项目开发-第七部分 获取角色路径_3

    点击下载代码   http://download.csdn.net/detail/lideguo1979/8291803 新建一个类RouteNavigation,定义getPath()方法.用来获取 ...

  7. Java 获取到配置文件信息

    Java程序将数据库或者服务器IP写入到代码中,难免缺少灵活性. 如果写入到配置文件,部署到不通服务器上,只需要修改配置文 件即可. Java怎么读取配置文件 /** * 获取到配置文件信息 * @p ...

  8. git项目同时支持多个远端仓库

    git项目同时支持多个远端仓库 为了防止github被墙,最好在国内的托管商做一个备份,这就需要同时提交到多个远端仓库,例如一个open source项目同时要提交csdn和github,url分别是 ...

  9. 用户界面线程AfxBeginThread的使用

    用户界面线程在运行时会有一个窗口界面和与其相对应的窗口函数,所以它可以通过响应消息来和用户进行交互. AfxBeginThread 函数原型如下: CWinThread *AfxBeginThread ...

  10. 使用Eclipse EE开发web项目

    最近使用EclipseEE开发web项目,遇到了以下几个问题: 1. 通过tomcat启动web应用的时候,总是提示找不到包或者class. 经过排查,发现所有的jar包并没有放到WEB-INF/li ...