使用Java解压缩并重新打包jar会导致jar文件损坏

时间:2012-07-27 18:58:05

标签: java jar io compression zip

我一直在调试一些jar-update片段,我遇到了一个zip / unzip组合应该可以反转另一个,但是当我在jar上尝试它时,即使所有文件都存在,它也会失败。任何人都可以找出出错的地方吗?

SSCCE(无需编译):Download here!

package jarsscce;

import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;

public class JarSSCCE {

    public static void main(String[] args) throws IOException {
        File testJar = new File("test.jar");
        File testDir = new File("test");
        File jarPack = new File("packed_test.jar");

        unpack(testJar, testDir);
        jar(testDir, jarPack);
    }

    public static void jar(File directory, File zip) throws IOException {
        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(zip))) {
            jar(directory, directory, jos);
        }
    }

    private static void jar(File directory, File base, JarOutputStream jos) throws IOException {
        File[] files = directory.listFiles();
        byte[] buffer = new byte[1 << 12];

        if (files.length == 0) {
            JarEntry entry = new JarEntry(directory.getPath().substring(base.getPath().length() + 1) + File.separator);
            jos.putNextEntry(entry);
        } else {

            for (int i = 0, n = files.length; i < n; i++) {
                if (files[i].isDirectory()) {
                    jar(files[i], base, jos);
                } else {
                    try (FileInputStream in = new FileInputStream(files[i])) {
                        JarEntry entry = new JarEntry(files[i].getPath().substring(base.getPath().length() + 1));
                        jos.putNextEntry(entry);

                        int read;
                        while ((read = in.read(buffer, 0, buffer.length)) != -1) {
                            jos.write(buffer, 0, read);
                        }
                        jos.closeEntry();
                    }
                }
            }
        }
    }

    public static void unpack(File zip, File extractTo) throws IOException {
        try (ZipFile archive = new ZipFile(zip)) {
            Enumeration e = archive.entries();
            while (e.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) e.nextElement();
                File file = new File(extractTo, entry.getName());
                if (entry.isDirectory() && !file.exists()) {
                    file.mkdirs();
                } else {
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    try (InputStream in = archive.getInputStream(entry)) {
                        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
                        byte[] buffer = new byte[1 << 13];
                        int read;
                        while ((read = in.read(buffer)) != -1) {
                            out.write(buffer, 0, read);
                        }
                        out.close();
                    }
                }
            }
        }
    }
}

编辑:通过Winrar查看存档信息,我可以看到Netbeans创建的test.jar根本没有压缩,而且程序创建的是。 “主机OS”和“要提取的版本”值也不同。虽然我看不出其中的任何一个会有多重要。

1 个答案:

答案 0 :(得分:2)

我想我已经找到了问题,在这个链接上有一个高峰:http://viralpatel.net/blogs/creating-zip-and-jar-files-in-java/。它讨论了使用entry.setMethod(ZipEntry.STORED)然而我们必须创建自己的校验和等,但它在链接中都有解释。

<强>附录:

使用不同的zip()方法让它工作:

import java.io.*;
import java.net.URI;
import java.util.Deque;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class Main {

    public static void main(String[] args) throws IOException {
        File testJar = new File("test.jar");
        File testDir = new File("test");
        File jarPack = new File("packed_test.jar");

        unpack(testJar, testDir);
        jar(testDir, jarPack);
    }

    public static void jar(File directory, File zipfile) throws IOException {
        URI base = directory.toURI();
        Deque<File> queue = new LinkedList<>();
        queue.push(directory);
        OutputStream out = new FileOutputStream(zipfile);
        Closeable res = out;
        try {
            ZipOutputStream zout = new ZipOutputStream(out);
            res = zout;
            while (!queue.isEmpty()) {
                directory = queue.pop();
                for (File kid : directory.listFiles()) {
                    String name = base.relativize(kid.toURI()).getPath();
                    if (kid.isDirectory()) {
                        queue.push(kid);
                        name = name.endsWith("/") ? name : name + "/";
                        zout.putNextEntry(new ZipEntry(name));
                    } else {
                        zout.putNextEntry(new ZipEntry(name));
                        copy(kid, zout);
                        zout.closeEntry();
                    }
                }
            }
        } finally {
            res.close();
        }
    }

    private static void copy(File file, OutputStream out) throws IOException {
        try (InputStream in = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            while (true) {
                int readCount = in.read(buffer);
                if (readCount < 0) {
                    break;
                }
                out.write(buffer, 0, readCount);
            }
        }
    }

    public static void unpack(File zip, File extractTo) throws IOException {
        ZipFile archive = new ZipFile(zip);
        Enumeration e = archive.entries();
        while (e.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            File file = new File(extractTo, entry.getName());
            if (entry.isDirectory() && !file.exists()) {
                file.mkdirs();
            } else {
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
                BufferedOutputStream out;
                try (InputStream in = archive.getInputStream(entry)) {
                    out = new BufferedOutputStream(
                            new FileOutputStream(file));
                    byte[] buffer = new byte[8192];
                    int read;
                    while (-1 != (read = in.read(buffer))) {
                        out.write(buffer, 0, read);
                    }
                }
                out.close();
            }
        }
    }
}

感谢这个问题我找到了java.util.zip - Recreating directory structure