Accessing resources inside a JAR [duplicate] - java

This question already has answers here:
How do I read a resource file from a Java jar file?
(9 answers)
Closed 5 years ago.
I'm making a test program for resource loading inside a jar and I'm having problems.
I've read that you should use ClassLoader or alternatively getClass() to access a file inside a jar. Since the method that i use to load the resource is static, I use ClassLoader.getSystemResource(String path).
My program finds the file but says that the path contains invalid syntax for filenames or directory names. This is the code that I use to load my resources:
String path = ClassLoader.getSystemResource(file).getPath();
System.out.println(path);
try {
wave = WaveData.create(new BufferedInputStream(new FileInputStream(path)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
AL10.alBufferData(buffers.get(i), wave.format, wave.data, wave.samplerate);
wave.dispose();
Yes, I'm loading soundfiles for OpenAL.
Anyway, I should remind you that it actually finds the file but the path has invalid syntaxing. This is an example of the path I get when I run it in jar form:
file:\C:\Users\name\development\jars\test.jar!\sounds\test.wav
I've tried to remove the "!" and I still get the same error. If i remove the "file:" it doesn't find the file. Note that the program runs fine when I'm running in Eclipse.

If you are getting a file from a jar use getResourceAsStream() and use the package names for the path.
getResourceAsStream("/com/project/resources/sounds/myfile.wav")

Not every URL corresponds to a file in file system. In particular, a particular entry in a JAR file isn't itself a file, and hence cannot be read with a FileInputStream. You can open an InputStream for a class path resource using Class.getResourceAsStream() or ClassLoader.getResourceAsStream().

Related

FileNotFoundException in the same directory [duplicate]

This question already has answers here:
Java, reading a file from current directory?
(8 answers)
FileNotFoundException even when the file is there
(3 answers)
Closed 9 days ago.
I'm not entirely sure if this is a Java issue or an IntelliJ issue, but I had a quick question about my File not being found via a path. My Main class is in the same directory as my input.txt file.
I though I should be able to do File file = new File("./input.txt"), except I get FileNotFoundException. When I do something like File file = new File("src/input.txt"), it does work.
I get that this may be a solution, but if I try to run this code outside of IntelliJ without a src directory, this will lead to an error where the File can't be found.
Is there any reason why I can't just do ./input.txt to specify that the File is in the same directory as the Main file?
That's because in IDEA, the working directory of your program is the root directory of your project, not src by default. Therefore, you can access the file by ./src/input.txt or src/input.txt, not input.txt. By the way, it's bad practice to put your resources in src, because it gets mixed with your source code, and it won't be included in the JAR file, which means you cannot access it when your project is packaged as a JAR file. If you are using maven, you can put input.txt inside the resources folder(src/main/resources), and access it by Main.class.getResource("/input.txt")(gives you a URL) or Main.class.getResourceAsStream("/input.txt")(gives you a InputStream) depending on your needs. So that the resources will always be available, no matter you are running the program in IDEA or from a JAR.
FileNotFoundException occurs when the file doesn't exist at the specified location.
File file = new File("./input.txt"), the current working directory (.) is being used as the file location.
If you are running the code from an IDE, the current working directory is usually the project root directory, not the directory where the code file is located.
So, if the input.txt file is located in the same directory as your code file, then you should use the relative path to it.
File file = new File("src/input.txt"), you are specifying the absolute path to the input.txt file, which is inside the src directory.
This is why it works, as the file is guaranteed to exist at that location.
If the file is located in the same directory as your code file, you can use a relative path, and if it's in a different directory, you should use an absolute path to it.

Java read and write to the resource folder

When someone opens my jar up I am opening a file selector gui so they can choose where they want to store their jar's files like config files and such. This should only take place the first time they open the jar. However, one issue with this approach is that I would have no way to know if it's their first time opening the jar since I will need to save the selected path somewhere. The best solution to this sounds like saving the selected path inside a file in the resource folder which is what I am having issues with. Reading and writing to this resource file will only need to be done when the program is actually running. These read and write operations need to work for packaged jar files (I use maven) and in the IDE.
I am able to read a resources file inside of the IDE and then save that file to the designated location specified in the file selector by doing this. However, I have not been able to do the same from a jar despite trying multiple other approaches from other threads.
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream("config.yml");
try {
if(is != null) {
Files.copy(is, testFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
So just to clarify when my project is loaded I need to listen for the user to select a valid path for files like my config. Then I want to write my config to that path which I can do from my IDE and is shown above but I cant figure this out when I compile my project into a jar file since I always receive a file not found error in my cmd. However, the main point of this post is so that I can figure out how to save that selected path to my resource folder to a file (it can be json, yml or whatever u like). In the code above I was able to read a file but I have no idea how to go from that to get the files path since then reading and writing to it would be trivial. Also keep in mind I need to be able to read and write to a resource folder from both my IDE and from a compiled jar.
The following code shows my attempt at reading a resource from a compiled jar. When I added a print statement above name.startWith(path) I generated a massive list of classes that reference config.yml but I am not sure which one I need. I assume it has to be one of the paths relating to my project or possible the META-INF or META-INF/MANIFEST.MF path. Either way how am I able to copy the file or copy the contents of the file?
final String path = "resources/config.yml";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if(jarFile.isFile()) { // Run with JAR file
try {
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(path)) { //filter according to the path
System.out.println(name);
}
}
jar.close();
} catch (IOException exception) {
exception.printStackTrace();
}
}
Also if you were wondering I got the above code from the following post and my first block of code I pasted above is actually in the else statement since the IDE code from that post also did not work.
How can I access a folder inside of a resource folder from inside my jar File?
You can't write to files inside your JAR file, because they aren't actually files, they are ZIP entries.
The easiest way to store configuration for a Java application is to use Preferences:
Preferences prefs = Preferences.userNodeForPackage(MyApp.class);
Now all you have to do is use any of the get methods to read, and put methods to write.
There is absolutely no need to write files into your resource folder inside a jar. All you need to have is a smart classloader structure. Either there is a classloader that allows changing jars (how difficult is that to implement?), or you just setup a classpath that contains an empty directory before listing all the involved jars.
As soon as you want to change a resource, just store a file in that directory. When loading the resource next time, it will be searched on the classpath and the first match is returned - in that case your changed file.
Now it could be that your application needs to be started with that modified classpath, and on top of that it needs to be aware which directory was placed first. You could still setup that classloader structure within a launcher application, which then transfers control to the real application loaded via the newly defined classloader.
You could also check on application startup whether a directory such as ${user.home}/${application_name}/data exists.
If not, create it by extracting a predefined zip into this location.
Then just run your application which would load/write all the data in this directory.
No need to read/write to the classpath. No need to include 3rd party APIs. And modifying this initial data set would just mean to distribute a new zip to be extracted from.

How to get directory of a .java file [duplicate]

This question already has answers here:
How to get the current working directory in Java?
(26 answers)
Closed 3 years ago.
Part of my (java) code needs to access a database. When opening a connection it checks if the actual database file exists (I use sqlite). I want to make my code portable, so I want to avoid hard coding the path of the database file. Is there anyway in java to get the path of the .java file? Because I know exactly where the database is from the .java file accessing it.
I've tried using current directory with File but it doesn't give me the path of the actual .java file. When I use android studio the current directory is different than when I simply use a terminal.
The best way to get the path information would be using Paths and Path class from the java.nio. You can input an absolute path or relative path to the Paths.get(String str) to get the Path.
To get the project directory, you can use:
Paths.get(System.getProperty(“user.dir”))
Paths.get(“”)
It will get the complete absolute path from where your application was initialized.
The Paths.get() method will return a Path Object, on which you can call toString() or toUri() to get the path. Hope this helps.
Javadocs - Paths

How can I read a file from the classpath in a JAR? [duplicate]

This question already has answers here:
How to get a path to a resource in a Java JAR file
(17 answers)
Closed 4 years ago.
I was using the following code to read a file from the classpath:
Files.readAllBytes(new ClassPathResource("project.txt").getFile().toPath())
This worked fine when project.txt was in src/main/resources of my WAR. Now I refactored code and moved certain code to a JAR. This new JAR now includes src/main/resources/project.txt and the code above. Now I get the following exception when reading the file:
java.io.FileNotFoundException: class path resource [project.txt]
cannot be resolved to absolute file path because it does
not reside in the file system:
jar:file:/usr/local/tomcat/webapps/ROOT/WEB-INF/lib/viewer-1.0.0-SNAPSHOT.jar!/project.txt
I'm still executing the WAR in a Tomcat container.
How can I fix this?
You cant refer the file from jar the way you do it in from resources. Since the file is packaged inside the jar you need to read it as resource.
You have to read the file as resource using classloader.
sample code:
ClassLoader CLDR = this.getClass().getClassLoader();
InputStream inputStream = CLDR.getResourceAsStream(filePath);
If you are using java 8 and above then you can use below code using nio to read your file:
final Path path = Paths.get(Main.class.getResource(fileName).toURI());
final byte[] bytes = Files.readAllBytes(path);
String fileContent = new String(bytes, CHARSET_ASCII);

Java getting a .wav file to run inside a .jar [duplicate]

This question already has answers here:
Load a resource contained in a jar
(3 answers)
Closed 8 years ago.
I am trying to get my .wav file to run from inside a .jar file once I have exported the program, and have researched extensively on the solution, but have found nothing that works.
Here is my current code:
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File("soundfile.wav")));
clip.start();
What can I do to fix this?
A resource contained within the context of a Jar file is commonly known as an embedded resource.
These resources can not be accessed like normal file system resources (ie via the File class), instead, you need to use Class#getResource, which will return a URL, which can be, in you case, passed to AudioSystem.getAudioInputStream
You could use something like...
clip.open(AudioSystem.getAudioInputStream(getClass().getResource("/path/to/resources/soundfile.wav")));
In this example, the path is relative to the package location of the class instance. That means if the resource is in another directory, you will need to to provide a full path to the resource

Categories

Resources