How Can My Java Program Store Files Inside of Its .Jar File

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.

How to list the files inside a JAR file?

CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream(jar.openStream());
while(true) {
ZipEntry e = zip.getNextEntry();
if (e == null)
break;
String name = e.getName();
if (name.startsWith("path/to/your/dir/")) {
/* Do something with this entry. */
...
}
}
}
else {
/* Fail... */
}

Note that in Java 7, you can create a FileSystem from the JAR (zip) file, and then use NIO's directory walking and filtering mechanisms to search through it. This would make it easier to write code that handles JARs and "exploded" directories.

How can an app use files inside the JAR for read and write?

I need to store data into files inside .jar file and read it again

No you don't.

Instead store the 'default' file inside the Jar. If it is changed, store the altered file in another place. One common place is a sub-directory of user.home. When checking for the file, first check the existence of an altered file on the file system, and if it does not exist, load the default file.


Note that it is generally better to describe the goal, rather than the strategy. 'Store changed file in Jar' is a strategy, whereas 'Save preferences between runs' might be the goal.

Related: What is the XY problem?

Store a file inside a jar library

Keep the file in the src/main/resources directory and use the following method in the class where you need to load that file -

private InputStream readFileFromResourcePath(String filename) {
return getClass().getClassLoader().getResourceAsStream(filename);
}

Do not forget to close the stream after consuming it.

Reading a resource file from within jar

Rather than trying to address the resource as a File just ask the ClassLoader to return an InputStream for the resource instead via getResourceAsStream:

try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}

As long as the file.txt resource is available on the classpath then this approach will work the same way regardless of whether the file.txt resource is in a classes/ directory or inside a jar.

The URI is not hierarchical occurs because the URI for a resource within a jar file is going to look something like this: file:/example.jar!/file.txt. You cannot read the entries within a jar (a zip file) like it was a plain old File.

This is explained well by the answers to:

  • How do I read a resource file from a Java jar file?
  • Java Jar file: use resource errors: URI is not hierarchical

How to Create a Jar that uses a file to save app information to

Jar files are read only, that means you can't save informations inside the jar. You can save files inside an read them but you can't edit them.

In your case there are more or less two options:

  1. Save the *.json file in e.g the OS Temp path or somewhere else where you can read and write them.
  2. Handle like zip - https://stackoverflow.com/a/4056713/8087490 -

    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.

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

How to create a file/folder from jar in Java?

getResource will retrieve a path into the JAR file, in case the class file is also coming from there; otherwise a normal path, if not running from JAR.

Use a plain File to get a path to a file/directory (e.g. new File("data/files/")) that is not saved in the JAR



Related Topics



Leave a reply



Submit