如何编写可以提取 JAR 文件并将其数据存储在指定目录(位置)中的 Java 程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1529611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:52:48  来源:igfitidea点击:

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

javajar

提问by Sunil Kumar Sahoo

I have created a JARfile. 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.

我创建了一个JAR文件。现在,我创建了另一个 Java 程序。我想将该 JAR 文件解压缩到其他目录中,这意味着我想做诸如解压缩之类的操作。

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

如果我运行jar -xf filename.jar这会导致一些错误:

Exception in thread "main" java.io.IOException: Cannot run program "jar": 
java.io.IOException: error=2, No such file or directory
     at java.lang.ProcessBuilder.start(ProcessBuilder.java:459)
     at java.lang.Runtime.exec(Runtime.java:593)`

采纳答案by JuanZe

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

改编此示例:如何从 JAR 和 zip 存档中提取 Java 资源

Or try this code:

或者试试这个代码:

Extract the Contents of ZIP/JAR Files Programmatically

Suppose jarFileis the jar/zip file to be extracted. destDiris 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();

以编程方式提取 ZIP/JAR 文件的内容

假设jarFile是要解压的 jar/zip 文件。destDir是它将被提取的路径:

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

来源http: //www.devx.com/tips/Tip/22124

回答by DigitalRoss

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.

您的标题似乎与问题不太匹配,但如果您真的想“编写 [a] java 程序提取 jar 文件”,您只需要Class JarFile

回答by adatapost

JarFileclass.

JarFile类。

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

回答by Arpit

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.

您可以使用此代码片段作为参考来完成您的任务。它几乎与@JuanZe 上面显示的代码片段相同,除了那些收到 FileNotFoundException 的人,我添加了一个小代码片段来检查是否文件确实存在,如果不存在,那么它将与文件一起创建父文件夹,并将在指定的目标文件夹中提取 jar 文件的内容。

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

  }

}

回答by Jamesst20

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.

这是我从 jar 中提取整个“资源”文件夹的方法。使用 BufferedReader 和 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;
}

回答by ReaperSoon

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

您可以使用这个非常简单的库来打包/解包 jar 文件

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

你也可以使用maven 依赖

<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 trackerif you find some bugs

如果您发现一些错误,请使用我的公共问题跟踪器

回答by Adam

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

好吧,这是我的版本,使用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);
    }

回答by davidxxx

Old question.
Here is a updated answer using :

老问题。
这是使用以下内容的更新答案:

  • Java 7 java.nioto create and copy efficiently entries
  • Java 8 streamto sort and collect the entries lexicographically (in order to always create folders first).
  • Java 7java.nio高效地创建和复制条目
  • Java 8stream按字典顺序对条目进行排序和收集(以便始终首先创建文件夹)。

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/ZipEntryby JarFile/JarEntry.

请注意,我使用了java.util.zip.ZipFile(基类)而不是java.util.jar.JarFile(子类)。
最后一个执行更多不需要“仅”从存档中提取文件的操作。
因此,它减少了开销并防止了与安全问题相关的异常上升。但如果需要,您当然可以替换ZipFile/ZipEntryJarFile/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);
            }
        }

    }
}

回答by rustyx

In case anyone is interested..

如果有人有兴趣..

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

这是使用缓冲 I/Otry-with-resources 的Java 7+版本。

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