附加 zip 存档调试

2022-01-22 00:00:00 file append zip exception java

所以我对将文件附加到 zip 存档很感兴趣,我遇到了一些以前问过这个问题的用户,另一个用户给出了这个代码片段作为该问题的解决方案:

So I was interested in appending files to a zip archive and I came across a few users who asked this question before and another user gave this code snippet as a solution to that problem:

    public static void updateZip(File source, File[] files, String path){
    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[4096];
        ZipInputStream zin = new ZipInputStream(new FileInputStream(tmpZip));
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(source));
        for(int i = 0; i < files.length; i++){
            System.out.println(files[i].getName()+"being read");
            InputStream in = new FileInputStream(files[i]);
            out.putNextEntry(new ZipEntry(path + 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()){
            if(!zipEntryMatch(ze.getName(), files, path)){
                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();
    }
}

private static boolean zipEntryMatch(String zeName, File[] files, String path){
    for(int i = 0; i < files.length; i++){
        if((path + files[i].getName()).equals(zeName)){
            return true;
        }
    }
    return false;
}

我创建了一个小程序来测试这个方法,这是完成所有工作的方法:

I created a mini program to test out this method and this is the method that does all the work:

    private static void appendArchive() {
    String filename = "foo";
    File[] filelist = new File[10];
    int i = 0;
    String temp = "";
    while (!filename.trim().equals("")) {
        System.out
                .println("Enter file names to add, then enter an empty line");
        filename = getInput();
        filelist[i] = new File(filename, filename);
        System.out.println("Adding " + filelist[i].getName());

    }
    System.out
            .println("What is the name of the zip archive you want to append");
    File zipSource = new File(getInput() + ".zip", "testZip.zip");
    try {
        Archiver.updateZip(zipSource, filelist, "");
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

每当我尝试运行这个程序时,我都会收到这个错误,然后是下一个:

Whenever I try to run this program I get this error, followed by the next one:

java.lang.Exception: Could not make temp file (testZip.zip)

at Archiver.updateZip(Archiver.java:68)
at main.appendArchive(main.java:62)
at main.main(main.java:29)

我怀疑我传递的 zip 文件由于某种原因被认为是打开的,因此重命名方法在 Windows 上不起作用,所以我尝试使用您现在看到的 zip 文件的构造函数.我到底在做什么错在这里.我的测试输入是文件 2 和 2(附加到 2.zip ).它不应该是任何与目录相关的问题,因为文件是由程序生成的.

I suspected that the zip file I was passing was considered open for some reason, and so the rename method wasn't working on windows so I instead tried using the constructor for zip file you see now. What exactly am I doing wrong here. My test input is 2 for the file, and 2(which is appended to 2.zip ). It shouldnt be any directory related issues since the files are generated by the program.

推荐答案

为我找到作品.我怀疑你可能想检查 tmpZip.delete() 的操作.

Works find for me. I suspect you might want to check the operation of tmpZip.delete().

if (!tmpZip.exists() || tmpZip.delete()) {
    // ... Continue
} else {
    // ... File is locked
}

更新

我一直在玩代码,还有一些额外的缺陷......

I've been playing around with the code and there are some additional flaws...

将旧条目添加到新文件时,您使用的是现有的 ZipEntry 条目.如果结果压缩不同,这将失败.您应该创建一个新的 ZipEntry 添加使用它来代替

When adding in the old entries to the new file, you are using the existing ZipEntry entry. This will fail if the resulting compression is different. You should create a new ZipEntry add use that instead

ZipEntry ne = new ZipEntry(ze.getName());
out.putNextEntry(ne);
// Write bytes to file...
out.closeEntry();

你永远不会关闭 ZipInputStream 这意味着 tmpZip.delete() 最后会失败.

You never close the ZipInputStream which means tmpZip.delete() at the end will fail.

你的错误处理几乎不存在......

You're error handling is next to non existent...

ZipInputStream zin = null;
ZipOutputStream out = null;
try {
    // Append zip ...
} finally {
    try {
        zin.close();
    } catch (Exception exp) {
    }
    try {
        out.close();
    } catch (Exception exp) {
    }
}

将防止未来的文件锁定(我故意没有捕获 IOException,因为我个人认为它应该被扔回被调用者)

Will prevent future file locks (I've deliberately not caught the IOException as I personally believe it should be thrown back to the called)

在完成之前,您不应覆盖现有的 zip 文件.您应该为新的 zip 文件创建一个临时文件,将所有文件写入其中,附加现有文件,完成后,将现有文件替换为临时文件.

You shouldn't overwrite the existing zip file UNTIL you have finished. You should create a temporary file for the new zip file, write all the files into it, append the existing files and once your done, replace the existing file with the temporary one.

这意味着,如果出现问题,您并没有破坏现有的 zip 文件.

This means, if something should go wrong, you've not destroyed the existing zip file.

恕我直言

相关文章