How to Write a Java Program Which Can Extract a Jar File and Store Its Data in Specified Directory (Location)

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

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

Extract directory from jar file

An answer from this thread might give a good feeling how/where to start:

  • How to extract Java resources from JAR and zip archive

Simply put, it's java.util.jar you're looking for.

Extracting jar to specified directory

It's better to do this.

Navigate to the folder structure you require

Use the command

jar -xvf  'Path_to_ur_Jar_file'

How can i make a simple self extracting jar file?

A self-extracting jar (still needing a java installation)

package com.stackoverflow.joopeggen;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.*;
import java.security.ProtectionDomain;
import java.util.Map;

public class App {

public static void main(String[] args) {
try {
new App().extractSelf();
} catch (IOException | URISyntaxException| IllegalStateException e) {
e.printStackTrace();
System.exit(1);
}
}

The extraction uses class information to get the jar source URL file: ... .jar.

    private void extractSelf() throws IOException, URISyntaxException {
ProtectionDomain protectionDomain = App.class.getProtectionDomain();
URL fileUrl = protectionDomain.getCodeSource().getLocation();
// "file: ... .jar"
Path jarDir = Paths.get(fileUrl.toURI()).getParent();
URI jarFileUri = URI.create("jar:" + fileUrl);
Map<String, Object> env = Map.of("Encode", "UTF-8");
FileSystem zipFS = FileSystems.newFileSystem(jarFileUri, env);
Path root = zipFS.getPath("/");
Files.list(root)
.filter(path -> Files.isRegularFile(path))
.forEach(path -> {
try {
Path extractedPath = jarDir.resolve(path.getFileName().toString());
System.out.println("* " + extractedPath);
Files.copy(path, extractedPath);
} catch (IOException e) {
throw new IllegalStateException(path.getFileName().toString(), e);
}
});
}
}

The main class needs to be inside the META-INF/MANIFEST.MF.

I have used maven for the build.

  • src/main/java - the root for java sources
    • com/stackoverflow/joopeggen - the package
  • src/main/resources - the root for resource files
    • cert.pem
    • cloudflare.exe

As you might not be familiar with maven, the Project-Object-Model XML, pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.stackoverflow.joopeggen</groupId>
<artifactId>selfextracting</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<!-- exec:exec to start the jar instead of generated classes. -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>maven</executable>
</configuration>
</plugin>
<plugin>
<!-- To fill META-INF/MANIFEST.MF with Main-Class. -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.stackoverflow.joopeggen.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

The code only requires a few lines (approx. 17), though many aspects are touched.

Extract a directory from a jar

If you want to access the resources from a JAR that is on the classpath at runtime, you simply access the resources from the classpath. So no need to read it via the JAR API. Therefore your first link points to a valid solution.

It may be tricky to use the appropriate classloader. If your resource is in the same folder as a Java class file, this link may help you: How to access resources in JAR file?

URL url = getClass().getResource("path/to/img.png");

or

URL url = MyClass.class.getResource("path/to/img.png");

I think you could access the two files separately and store them to a file. There are also methods to open a stream to copy. Here is a similar question: getResourceAsStream returns null

Extracting a file from the currently running JAR through code

Use getResourceAsStream (docs), you can do whatever you want with it after that.

For a two-liner you could use one of the Commons IO copy methods.

How can my Java program store files inside of its .jar file?

Yes you can do this.

Non-code resources in a JAR file on the classpath can be accessed using Class.getResourceAsStream(String). Applications routinely do this, for example, to embed internationalized messages as resource bundles.

To get your file into the JAR file (at project build time!), just copy it into the appropriate place in the input directory tree before you run the jar command. Build tools such as Maven, Gradle, etc can automate that for you.



Is there a way to add files to the archive within the app?

In theory, your application could store files inside its own JAR file, under certain circumstances:

  • The JAR has to be a file in the local file system; i.e. not a JAR that was fetched from a remote server.
  • The application has to have write access to the JAR file and its parent directory.
  • The application must not need to read back the file it wrote to the JAR in the current classloader; i.e. without exiting and restarting.
  • The JAR must not need to be be signed.

The procedure would be:

  1. Locate the JAR file and open as a ZIP archive reader.
  2. Create a ZIP archive writer to write a new version of JAR file.
  3. Write the application's files to the writer.
  4. Write all resources from the ZIP reader to the writer, excluding old versions of the applications files.
  5. Close the reader and writer.
  6. Rename the new version of the JAR to replace the old one.

The last step might not work if the initial JAR is locked by the JVM / OS. In that case, you need do the renaming in a wrapper script.

However, I think that most people would agree that this is a BAD IDEA. It is simpler and more robust to just write regular files.



Related Topics



Leave a reply



Submit