Access file in jar file?
You could use something like this:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileFromJarFile);
If foo.txt was in the root of your JAR file, you'd use:
InputStream is = this.getClass().getClassLoader().getResourceAsStream("foo.txt");
assumes the class is in the same JAR file as the resource, I believe.
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 access file within jar file?
I don't know the exact reason for why it wasn't working but changing these two lines
input = this.getClass().getResourceAsStream("auth");
prop.load(input);
to these:
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
input = classloader.getResourceAsStream("auth");
prop.load(input);
made my code working
Accessing a file inside a .jar file
When your resourse is in JAR file, it's not a File anymore. A File is only a physical file on the filesystem.
Solution: use getResourceAsStream. Something like this:
new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/resources/" + filename)))
access files and folders in executable jars
When you're using a jar file, those files don't exist as files any more.
You can absolutely include the data in your jar file, but then you'll need to change the code which accesses it, too. Instead of creating a File
object, you'll need something like:
InputStream input = Foo.class.getResourceAsStream("/dataFolder/Folder1/file.xml");
So you have two separable tasks:
- Work out how to include the data folder within your jar file
- Change your code to access the data appropriately
Getting resource file from inside jar
Maven uses something called the Standard Directory Layout. If you don't follow this layout then the plugins can't do their job correctly. Technically, you can configure Maven to use different directories but 99.999% of the time this is not necessary.
One of the features of this layout is that production files go in:
<project-dir>/src/main/java
- All
*.java
files
- All
<project-dir>/src/main/resources
- All non-
*.java
files (that are meant to be resources)
- All non-
When you build your project the Java source files are compiled and the *.class
files are put into the target/classes
directory; this is done by the maven-compiler-plugin
. Meanwhile, the resource files are copied from src/main/resources
into target/classes
as well; the maven-resources-plugin
is responsible for this.
Note: See Introduction to the Build Lifecycle for more information about phases and which plugins are executed by which phase. This Stack Overflow question may also be useful.
When you launch your application from the IDE (possibly via the exec-maven-plugin
) the target/classes
directory is put on the classpath. This means all the compiled classes from src/main/java
and all the copied resources from src/main/resources
are available to use via the classpath.
Then, when you package your application in a JAR file, all the files in target/classes
are added to the resulting JAR file (handled by the maven-jar-plugin
). This includes the resources copied from src/main/resources
. When you launch the application using this JAR file the resources are still available to use via the classpath, because they're embedded in the JAR file.
To make resource.txt
available on the classpath, just move:
<project-dir>/resource.txt
To:
<project-dir>/src/main/resources/resource.txt.
Then you can use Class#getResource
with /resource.txt
as the path and everything should work out for you. The URL
returned by getResource
will be different depending on if you're executing against target/classes
or against the JAR file.
When executing against target/classes
you'll get something like:
file:///.../<project-dir>/target/classes/resource.txt
When executing against the JAR file you'll get something like:
jar:file:///.../<project-dir>/target/projectname-version.jar!/resource.txt
Note: This all assumes resource.txt
is actually supposed to be a resource and not an external file. Resources are typically read-only once deployed in a JAR file; if you need a writable file then it's up to you to use a designated location for the file (e.g. a folder in the user's home directory). One typically accesses external files via either java.io.File
or java.nio.file.*
. Remember, resources are not the same thing as normal files.
Now, if you were to put resource.txt
directly under <project-dir>
that would mean nothing to Maven. It would not be copied to target/classes
or end up in the JAR file which means the resource is never available on the classpath. So just to reiterate, all resources go under src/main/resources
.
Check out the Javadoc of java.lang.Class#getResource(String)
for more information about the path, such as when to use a leading /
and when not to. The link points to the Javadoc for Java 12 which includes information about resources and modules (JPMS/Jigsaw modules, not Maven modules); if you aren't using modules you can ignore that part of the documentation.
Accessing files inside a jar file
That's because the file is inside the JAR and is no longer accessible on the file system - using a FileInputStream
is still using files.
You need to treat it as a resource instead and get an InputStream
from that, then it will work both when packaged as a JAR and when not.
h = t.getResponseHeaders();
os = t.getResponseBody();
// Get an URL to the file
URL url = getClass().getResource("GreetingText.html");
// Open the stream and read the contents into a byte array
byte[] bytes;
try(InputStream in = url.openStream();
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) > 0) {
bytes.write(buffer, 0, read);
}
bytes = out.toByteArray();
}
h.add("Content-Type", "text/html");
t.sendResponseHeaders(200, bytes.length);
os.write(bytes, 0, bytes.length);
os.close();
Place the file on your classpath, if it's in another package you need to prefix the path with /path/to/file, so if you put it in the directory html at the root of your classpath you will have to use "/html/GreetingText.html"
.
Related Topics
Java Web Start Support in Java 9 and Beyond
How to Handle Precision Error with Float in Java
Can't Transparent and Undecorated Jframe in Jdk7 When Enabling Nimbus
Arrayindexoutofboundsexception When Iterating Through All the Elements of an Array
Wrap the String After a Number of Characters Word-Wise in Java
Simpledateformat Parse(String Str) Doesn't Throw an Exception When Str = 2011/12/12Aaaaaaaaa
Refreshing Gui by Another Thread in Java (Swing)
Java Jdbc Access Denied for User
How to Correctly Use Custom Renderers to Paint Specific Cells in a Jtable
Including Images with an Executable Jar
What Is the Purpose of Defining a Package in a Java File
Keeping the Correct Style on Text Retrieval
Spring Qualifier and Property Placeholder
Cannot Find Firefox Binary in Path. Make Sure Firefox Is Installed
What Is the Priority of Casting in Java
Java Swing; Two Classes, Where to Put If Statements and New Actionlisteners