Access resources in a jar

Normally you would not even have to bother with this; imagine you have an application that uses a FilenameFilter to retrieve some resource from within your project. Say you want to load all image files in a specific location that conform to „/images/imagePrefix*_imageSuffix.png“. To create a FilenameFilter to retrieve a list of all file names that conform to that pattern is not that difficult. So you have an application that runs happily ever after … until you create a jar file from your project.

The problem here is that you can only access resources with a specific name in a jar file. Directories as on the file system are implicit and can therefore not be accessed.

In this case you have to differ if your application runs based on the file system or from a jar file. This first part is checked with this method:

/**
 * check if this class is inside a jar file
 * @return true if the class is inside a jar file
 */
public boolean isInJarFile(){
	URL res =getClass().getResource(getClass().getSimpleName()+".class");
	return "jar".equals(res.getProtocol());
}

Now if the resource is not inside a jar file we can easily list all the concrete image names in the directoryIMAGE_DIR:

/**
 * retrieve all filenames that match the corresponding filter in the image directory
 * @param filenamefilter something of the form firstfilenamepart*counter.ext
 * @return List of filenames
 * @throws URISyntaxException 
 */
protected final String[] getAvailableFilenames(String filenamefilter){
	try {
		URL url = getClass().getResource(IMAGE_DIR);
		final File imageDir = new File(url.toURI());
		final String head = filenamefilter.substring(0, filenamefilter.indexOf('*'));
		final String tail = filenamefilter.substring(filenamefilter.indexOf('*')+1);
		FilenameFilter filter = new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				if (dir.equals(imageDir)){
					if (name.startsWith(head) && name.endsWith(tail)){
						return true;
					}
				}
				return false;
			}
		};
		return imageDir.list(filter);
	} catch (URISyntaxException e) {
		e.printStackTrace();
		return new String[]{};
	}
}

The other case is basically straight forward as well. I had some help with this article. You have to look inside the jar file and navigate through the structure. Once you have retrieved concrete filename they can be retrieved by
getClass().getRessource(IMAGE_DIR+fileName).

To demonstrate this I created a maven project that prints out the first line of any file (not a class file) in a specific directory. If you run the main program directly the files are found within the project and read from file system. However if you create a jar and then run it, thy are read from within the jar file.

mvn package
java -jar target/loader-0.0.1-SNAPSHOT.jar

The package can be downloaded.

Schreibe einen Kommentar