使用Java将文件附加到zip文件

Gro*_*hal 56 java zip war truezip

我目前正在提取war文件的内容,然后将一些新文件添加到目录结构,然后创建一个新的war文件.

这一切都是以编程方式从Java完成的 - 但是我想知道复制war文件然后只是附加文件会不会更有效 - 那么我就不必等待战争扩展然后必须再次压缩.

我似乎无法在文档或任何在线示例中找到这样做的方法.

任何人都可以提供一些提示或指示?

更新:

其中一个答案中提到的TrueZip似乎是一个非常好的java库附加到一个zip文件(尽管其他答案说它不可能这样做).

任何人都有关于TrueZip的经验或反馈,或者可以推荐其他类似的图书馆?

Grz*_*Żur 79

在Java 7中,我们获得了Zip文件系统,允许在zip(jar,war)中添加和更改文件,无需手动重新打包.

我们可以直接写入zip文件中的文件,如下例所示.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,默认情况下 ZipFileSystem [易受 OutOfMemoryError 影响](http://stackoverflow.com/questions/23858706/zipping-a-huge-folder-by-using-a-zipfilesystem-results-in-outofmemoryerror) 在大量输入上。 (3认同)
  • Zip文件系统无法真正处理文件夹结构中的空格.要解决此问题,请使用"%2520"对所有空格进行编码(另请参阅http://stackoverflow.com/questions/9873845/java-7-zip-file-system-provider-doesnt-seem-to-accept-spaces-in - ) (2认同)
  • 使用 Files.copy 代替:尝试 (FileSystem jarFs = FileSystems.newFileSystem(uri, env, null)) { for(final Path newFilePath : newFilePathList) { Final Path pathInZipFile = jarFs.getPath("/" + newFilePath.getFileName()) ; Files.copy(newFilePath, pathInZipFile, StandardCopyOption.REPLACE_EXISTING); } } (2认同)
  • 这个答案展示了如何做到这一点,但它在幕后是如何工作的呢?更新 zip 中的文件是否高效,或者是否相当于解压缩并构建新的 zip? (2认同)

sfu*_*ger 44

正如其他人所提到的,不可能将内容附加到现有的zip(或战争).但是,可以动态创建新的zip,而无需将提取的内容临时写入磁盘.很难猜测它会有多快,但它是用标准Java获得的最快(至少据我所知).正如Carlos Tasada所提到的,SevenZipJBindings可能会挤出你一些额外的时间,但是将这种方法移植到SevenZipJBindings仍然比使用具有相同库的临时文件更快.

这里有一些编写现有zip(war.zip)内容的代码,并将一个额外的文件(answer.txt)附加到一个新的zip(append.zip).所需要的只是Java 5或更高版本,不需要额外的库.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用此方法获得_ZipException - 无效条目压缩size_,请参阅http://www.coderanch.com/t/275390/Streams/java/ZipException-invalid-entry-compressed-size (5认同)
  • @Grouchal实际上你不会需要比"BUFFER"更多的内存(我选择4MB,但你可以根据自己的需要自由定制 - 只有将它减少到几KB才不会有什么坏处).该文件永远不会完全存储在内存中. (3认同)

gnl*_*gic 25

我曾经有过类似的要求 - 但它是用于读取和编写zip档案(.war格式应该类似).我尝试使用现有的Java Zip流程,但发现写入部分很麻烦 - 尤其是涉及到的目录时.

我建议你试试TrueZIP(开源 - apache风格许可)库,将任何存档公开为虚拟文件系统,你可以像普通文件系统一样读写.它对我来说就像一个魅力,并大大简化了我的发展.

  • Java 7中有一个新选项,一个[ZipFileSystem](http://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html) (4认同)

Lia*_*rth 14

你可以使用我写的这段代码

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();
    }
}
Run Code Online (Sandbox Code Playgroud)