Java.util.zip adding a new file overwrites entire jar?(转)

 

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

 

时间: 2024-09-14 05:23:35

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

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

今天使用POI解析XLS,报错如下: Servlet.service() for servlet [rest] in context with path [/cetBrand] threw exception [Request processing failed; nested exception is org.apache.poi.openxml4j.exceptions.InvalidOperationException: Can't open the specified file: 'd:

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 with various unzip programs. It preserves the directory structure and timestamps. public static void createZipFile(File srcDir, OutputStream out, bo

使用java.util.zip实现文件压缩和解压

import java.io.*; import java.util.zip.*; /** *//** *功能:zip压缩.解压 *说明:本程序通过ZipOutputStream和ZipInputStream实现了zip压缩和解压功能. *问题:由于java.util.zip包并不支持汉字,当zip文件中有名字为中文的文件时 , author by http://www.bt285.cn http://www.5a520.cn * 就会出现异常:"Exception in thread &quo

java.util.zip创建和读取zip文件的类

写了一个用java.util.zip创建和读取zip文件的类 跟大家分享一下 里面用了递归调用 呵呵 近期用了不少递归调用!有空总结一下! /** TestZip.java coding by Serol Luo. rollingpig@163.com 2003/07/03 http://www.chinaunix.net/forum/viewforum.php?f=26 转载请保留此信息 */ import java.util.*; import java.util.zip.*; import

项目移到linux环境下时tomcat报错 java.util.zip.ZipException: invalid END header

问题描述 我把我的一个windows环境下的项目移到linux环境下时tomcat报错,报错如下:java.util.zip.ZipException: invalid END header (bad central directory offset)at java.util.zip.ZipFile.open(Native Method)at java.util.zip.ZipFile.<init>(ZipFile.java:114)at java.util.jar.JarFile.<i

java.util.zip.ZipOutputStream压缩无乱码(原创)

package io; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.zip.Adler32; import java.u

我的Android进阶之旅------&amp;gt;Android编译错误java.util.zip.ZipException: duplicate entry的解决方法

今天在Android Studio中把另外一个项目引入当前项目,编译的时候出现了java.util.zip.ZipException: duplicate entry错误. 错误如下所示: FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':watch:packageAllDebugClassesForMultiDex'. > java.util.zip.ZipExcept

java.util.zip.Deflater 压缩 inflater解压 实例

原文:java压缩解压缩类实例[转]   package com.example.helloworld; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.Deflater; import java.util.zip.Inflater; /** * ZLib压缩工具 * * @author 梁栋 * @version 1.0 * @since 1.0 */ public a

: java.util.zip.ZipException: duplicate entry: android/support/multidex/MultiDex$V14.class

问题描述 Error:Execution failed for task ':app:transformClassesWithJarMergingForBaiduDebug'.> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: android/support/multidex/MultiDex$V14.class 解决方案 http://www.itn