• 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

  • 相关阅读:
    Baidu aip创建TTS、ASR应用许可并申请免费试用
    网页设计与制作(基本步骤)
    2021新的一年要努力变强变好
    CentOS7查看和关闭防火墙
    CentOS7安装RabbitMQ
    uwsgi启动flask项目(venv虚拟环境)
    centos7 配置python虚拟环境以及使用-virtualenv
    uwsgi下载安装配置(四)http、http-socket和socket配置项详解
    Ubuntu 16.04安装Nginx
    uwsgi下载安装配置(三)uwsgi配置参数讲解
  • 原文地址:https://www.cnblogs.com/softidea/p/4272451.html
Copyright © 2020-2023  润新知