开发者

How to write a Java program which can extract a JAR file and store its data in specified directory (location)?

I have created a JAR file. Now, I created another Java program. I want to unpack that JAR file in some other directory, meaning I want to do something like unzip.

If I run jar -xf filename.jar this causes some error:

Exception in thread "main" java.io.IOException: Cannot run program "jar": 
java.io.IOException: error=2, No such file or dir开发者_如何学Cectory
     at java.lang.ProcessBuilder.start(ProcessBuilder.java:459)
     at java.lang.Runtime.exec(Runtime.java:593)`


Adapt this example: How to extract Java resources from JAR and zip archive

Or try this code:

Extract the Contents of ZIP/JAR Files Programmatically

Suppose jarFile is the jar/zip file to be extracted. destDir is the path where it will be extracted:

java.util.jar.JarFile jar = new java.util.jar.JarFile(jarFile);
java.util.Enumeration enumEntries = jar.entries();
while (enumEntries.hasMoreElements()) {
    java.util.jar.JarEntry file = (java.util.jar.JarEntry) enumEntries.nextElement();
    java.io.File f = new java.io.File(destDir + java.io.File.separator + file.getName());
    if (file.isDirectory()) { // if its a directory, create it
        f.mkdir();
        continue;
    }
    java.io.InputStream is = jar.getInputStream(file); // get the input stream
    java.io.FileOutputStream fos = new java.io.FileOutputStream(f);
    while (is.available() > 0) {  // write contents of 'is' to 'fos'
        fos.write(is.read());
    }
    fos.close();
    is.close();
}
jar.close();

Source: http://www.devx.com/tips/Tip/22124


You can use this code snippet as a reference to get your task done.Its almost the same as the code snippet shown above by @JuanZe except that for those who were getting the FileNotFoundException, i have added a small code snippet that will check if the file does exist and if it doesn't then it will create the parent folder along with the files and will extract the contents of jar file inside the specified destination folder.

Code snippet:

public class JarDemo {

  public static void main(String[] args) throws java.io.IOException {
    java.util.jar.JarFile jarfile = new java.util.jar.JarFile(new java.io.File("E:/sqljdbc4.jar")); //jar file path(here sqljdbc4.jar)
    java.util.Enumeration<java.util.jar.JarEntry> enu= jarfile.entries();
    while(enu.hasMoreElements())
    {
        String destdir = "E:/abc/";     //abc is my destination directory
        java.util.jar.JarEntry je = enu.nextElement();

        System.out.println(je.getName());

        java.io.File fl = new java.io.File(destdir, je.getName());
        if(!fl.exists())
        {
            fl.getParentFile().mkdirs();
            fl = new java.io.File(destdir, je.getName());
        }
        if(je.isDirectory())
        {
            continue;
        }
        java.io.InputStream is = jarfile.getInputStream(je);
        java.io.FileOutputStream fo = new java.io.FileOutputStream(fl);
        while(is.available()>0)
        {
            fo.write(is.read());
        }
        fo.close();
        is.close();
    }

  }

}


JarFile class.

JarFile file = new JarFile("file.jar");   
for (Enumeration<JarEntry> enum = file.entries(); enum.hasMoreElements();) {   
    JarEntry entry = enum.next();   
    System.out.println(entry.getName());   
} 


Here is what I would do to extract my whole "resources" folder from my jar. It is way more faster to use BufferedReader and BufferedWriter.

 public static boolean extractResourcesToTempFolder() {
    try {
        //If folder exist, delete it.
        String destPath = getTempDir() + File.separator + "JToolkit" + File.separator;
        deleteDirectoryRecursive(new File(destPath));            

        JarFile jarFile = new JarFile(JToolkit.class.getProtectionDomain().getCodeSource().getLocation().getPath());
        Enumeration<JarEntry> enums = jarFile.entries();
        while (enums.hasMoreElements()) {
            JarEntry entry = enums.nextElement();
            if (entry.getName().startsWith("resources")) {
                File toWrite = new File(destPath + entry.getName());
                if (entry.isDirectory()) {
                    toWrite.mkdirs();
                    continue;
                }
                InputStream in = new BufferedInputStream(jarFile.getInputStream(entry));
                OutputStream out = new BufferedOutputStream(new FileOutputStream(toWrite));
                byte[] buffer = new byte[2048];
                for (;;) {
                    int nBytes = in.read(buffer);
                    if (nBytes <= 0) {
                        break;
                    }
                    out.write(buffer, 0, nBytes);
                }
                out.flush();
                out.close();
                in.close();
            }
            System.out.println(entry.getName());
        }
    } catch (IOException ex) {
        Logger.getLogger(Methods.class.getName()).log(Level.SEVERE, null, ex);
        return false;
    }
    return true;
}


Old question.
Here is a updated answer using :

  • Java 7 java.nio to create and copy efficiently entries
  • Java 8 stream to sort and collect the entries lexicographically (in order to always create folders first).

Note that I used java.util.zip.ZipFile (the base class) instead of java.util.jar.JarFile (the subclass).
The last one performs more things that are not required to "just" extract files from an archive.
So it reduces the overhead and prevents exception rising related to security concerns. But if required you can of course replace ZipFile/ZipEntry by JarFile/JarEntry.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class FileUtils {

    public static void extractArchive(Path archiveFile, Path destPath) throws IOException {

        Files.createDirectories(destPath); // create dest path folder(s)

        try (ZipFile archive = new ZipFile(archiveFile.toFile())) {

            // sort entries by name to always create folders first
            List<? extends ZipEntry> entries = archive.stream()
                                                      .sorted(Comparator.comparing(ZipEntry::getName))
                                                      .collect(Collectors.toList());

            // copy each entry in the dest path
            for (ZipEntry entry : entries) {
                Path entryDest = destPath.resolve(entry.getName());

                if (entry.isDirectory()) {
                    Files.createDirectory(entryDest);
                    continue;
                }

                Files.copy(archive.getInputStream(entry), entryDest);
            }
        }

    }
}


Your title doesn't seem to match the question very well but if you really do want to "write [a] java program extracting a jar file" you just need Class JarFile.


You can use this very simple library to pack/unpack jar file

JarManager

Very simple

import java.io.File;
import java.util.List;

import fr.stevecohen.jarmanager.JarUnpacker;

class Test {
   JarUnpacker jarUnpacker = new JarUnpacker(); 
   File myfile = new File("./myfile.jar");
   File unpackDir = new File("./mydir");

   List<File> unpacked_files = jarUnpacker.unpack(myfile.getAbsolutePath(), unpackDir.getAbsolutePath());
}

You can also use maven dependency

<dependency>
    <groupId>fr.stevecohen.jarmanager</groupId>
    <artifactId>JarManager</artifactId>
    <version>0.5.0</version>
</dependency>

You also need my repository

<repository>
    <id>repo-reapersoon</id>
    <name>ReaperSoon's repo</name>
    <url>http://repo-maven.stevecohen.fr</url>
</repository>

Check the last version with the link bellow to use the last dependency

Please use my public issue tracker if you find some bugs


Well here's my version, using try-with-resources:

    try (JarFile jarFile = new JarFile(artifact.getFile())) {
        for (JarEntry entry : Collections.list(jarFile.entries())) {
            try (InputStream is = jarFile.getInputStream(entry)) {
                File file = new File(targetDir, entry.getName());
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    fos.write(is.read());
                }
            }
        }
    } catch (IOException e) {
        throw new MyException(String.format(
            "Unable to open jar %s", artifact.getArtifactId()), e);
    }


In case anyone is interested..

Here's a version for Java 7+ using buffered I/O and try-with-resources.

public static void unzip(File archive, File destDir) throws IOException {
    byte[] buffer = new byte[256 * 1024];
    destDir.mkdirs();
    try (JarFile jar = new JarFile(archive)) {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry ent = entries.nextElement();
            File f = new File(destDir, ent.getName());
            if (ent.isDirectory()) {
                f.mkdir();
                continue;
            }
            try (InputStream is = jar.getInputStream(ent);
                 FileOutputStream os = new FileOutputStream(f)) {
                for (int r; (r = is.read(buffer)) > 0; ) {
                    os.write(buffer, 0, r);
                }
            }
        }
    }
}


Here's my version, using Java 8 and org.apache.commons.io Its work for me.

File userDir = new File("resources");
userDir.mkdir();
JarFile jar = new JarFile("123.jar");
jar.stream()
   .filter(file -> 
    file.getName().contains("BOOT-INF/classes") && !file.getName().contains("BOOT-INF/classes/ch/"))
   .peek(file -> {
File res = new File(userDir.getPath() + file.getName().replaceAll("BOOT-INF/classes", ""));

     if (file.isDirectory()) {
          res.mkdirs();
     } else { try {
                  FileUtils.copyInputStreamToFile(jar.getInputStream(file), res);
            } catch (IOException e) {
                  System.out.println(e.getMessage());
            }
     }
     }).forEach(file -> LOGGER.info("Extract file: " + file.getName()));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜