El uso de Java para desempaquetar y volver a empaquetar un jar da como resultado un archivo jar roto

Estuve depurando algunos fragmentos de actualización de jar y encontré una combinación de comprimir/descomprimir que debería estar invirtiendo a la otra, pero cuando lo probé en un jar falló a pesar de que todos los archivos estaban presentes. ¿Alguien puede averiguar dónde está fallando esto?

SSCCE (no es necesario compilar): ¡Descarga aquí!

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();
                    }
                }
            }
        }
    }
}

EDIT: Mirando la información del archivo a través de Winrar, puedo ver que el test.jar creado por Netbeans no está comprimido en absoluto, y el creado por el programa sí lo está. Además, los valores "Host OS" y "Version to extract" son diferentes. Aunque no puedo ver cómo algo de eso sería significativo.

preguntado el 27 de julio de 12 a las 19:07

Simplemente dice que el archivo jar no es válido o está roto. -

1 Respuestas

Creo que he encontrado el problema, echa un vistazo a este enlace: http://viralpatel.net/blogs/creating-zip-and-jar-files-in-java/. habla de usar entry.setMethod(ZipEntry.STORED) sin embargo, luego tenemos que crear nuestras propias sumas de verificación, etc., pero todo se explica en el enlace.

Apéndice:

Lo tengo funcionando usando un diferente zip() método:

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();
            }
        }
    }
}

Todo gracias a esta pregunta que encontré :) java.util.zip - Recreación de la estructura del directorio

contestado el 23 de mayo de 17 a las 12:05

Ese es exactamente mi problema: debo estar perdiendo algún detalle muy pequeño en el empaque usando JarOutputStream eso permitiría que un jar creado funcione. Me molesta cómo es una tarea tan simple y, sin embargo, estoy sentado aquí durante horas tratando de resolverlo. >.< - rtheunissen

@paranoid-android Lol Lo sé. Mire la salida de los 2 frascos en un editor de texto... Varían mucho en formato. El método zip está haciendo algo divertido. Tuve un proyecto del mismo tipo hace un tiempo tratando de encontrar su código ahora: david kroukamp

Genial, gracias, avísame qué puedes encontrar. He estado buscando en Google esto durante horas, no puedo creer que no haya encontrado la publicación que vinculaste. Aunque acabo de tener una idea para crear un envoltorio usando las herramientas de Java jar, es decir. jar cf jarfile Etc.- rtheunissen

¡Eres una leyenda absoluta, David! Sin embargo, esto me deja preguntándome qué salió mal con el otro método zip. Pero me gusta este y creo que me lo quedo. Gracias de nuevo. +1 - rtheunissen

@paranoid-android :) Gracias y, para ser honesto, debe haber sido el formato que estaba usando para guardarlo, tal vez de alguna manera eso JarOutputStream lo estaba afectando? Aunque no soy 100% positivo - david kroukamp

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.