This question already has answers here:
How to read text file from classpath in Java?
(17 answers)
Closed 7 years ago.
I have a very simple method which uses the getclass().getResourceAsStream() method to read a file. However it always returns null and I can't figure out what is wrong. Here is my piece of code.
InputStream sw = getClass().getResourceAsStream("/filename.txt");
BufferedReader bf = new BufferedReader( new InputStreamReader(sw));
sw always remain null. the file filename.txt exist in the root directory of my project.
EDIT:
I found the reason. I realized that I was running my project from Eclipse and the project was not part of the classpath on my PC. However if I package my program as a jar file and then run it, the files in the jar file are considered as resources and can be read using the getResourceAsStream() method.
The method Class.getResourceAsStream() looks for the designated resource within the Java class path, not based on the project root.
The project root usually is not part of the classpath. Instead, you should have a src folder (or a similar name), which contains the Java files and may also contain your text file. Or, if you use Maven, you have folders src/main/java and src/main/resources, which are classpath roots. In this case, the text file should reside in the resources folder.
If your project gets packaged into a .jar file, all its resources are packaged in the .jar file along with the .class files, and will be found by Class.getResourceAsStream().
Root of your project is not always the root of the path from the ClassLoader point of view.
Easiest way to find out where it is trying to load the resource from:
System.out.println(MyClass.class.getResource("/").getPath());
And after that you may be able to easily find out the part of the project or run configuration that causes the difference between your assumption and the reality about the right placement of the file.
getResourceAsStream() reads a resource file, ie a file into .jar file (or resource directory), not a regular file in working directory on disk. Use FileReader to read a file from disk
user likewise,
InputStream sw = this.class.getClassLoader().getResourceAsStream("filename.txt");
Note : filename.txt file should be present on classpath.
Just to be complete, here's a simple test that does print out the absolute path of a resource. You can use this inside any class to find the location of that class on your hard drive, in case it isn't obvious what your build system is doing. Just substitute the name ErrorTest for the class you are checking.
public class ErrorTest
{
public static void main(String[] args )
{
final String className = ErrorTest.class.getSimpleName().replace( '.', '/').concat(".class");
System.out.println(ErrorTest.class.getResource(className).getPath() );
}
}
Output of this program:
run:
/C:/Users/Brenden/Google%20Drive/proj/tempj8/build/classes/quicktest/ErrorTest.class
BUILD SUCCESSFUL (total time: 0 seconds)
Related
I have a project with a folder "src/main/resources" where inside there is the hibernate configuration file, I load it using this line of code
HibernateUtil.class.getResource("/hibernate.cgf.xml").getPath()
From inside the IDE it is working well, but when I create the jar it doesn't file the file.
How can I load it properly in the jar file too?
Thanks
Could you please try this:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("fileName").getFile());
I cannot say for ceratin that this is the issue without knowing how exactly you use the path extracted by:
HibernateUtil.class.getResource("/hibernate.cgf.xml").getPath()
but I can tell you this:
Run from an IDE the above line of code will return:
/path/to/project/src/main/resources/hibernate.cgf.xml
which is a valid filesystem path. You can then use this path to, for example, create an instance of File class and then use that instance to read the file contents.
However the same line of code run from inside a jar file will return:
file:/path/to/jar/jar_name.jar!/hibernate.cgf.xml
which is not a valid filesystem path. If you create an instance of File class using this path and then try to read the contents of the file you'll get an exception: java.io.FileNotFoundExeption
To read the contents of the file from inside of a jar you should use method Class.getResourceAsStream(String), which will return an instance of class sun.net.www.protocol.jar.JarURLConnection.JarURLInputStream (or equivalent in non-Oracle or non-OpenJDK Java). You can then use this object to read the contents of the file. For example:
InputStream inputStream = HibernateUtil.class.getResourceAsStream("/hibernate.cgf.xml");
Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
String fileContents = scanner.hasNext() ? sscanner.next() : "";
Most likely, the file is absent from the jar you create. There's too little information in your question, but I will try a guess:
Your hibernate.cgf.xml resides in the same directory as the Java sourcefles, and you are using a build tool (be it IDE, maven, gradle or an ant script) that expects resources to be stored in a separate directory.
It's easy to check: try to unzip your jar and see if the file is there (use any tool, you can just change the extension from .jar to .zip). I think you will see the file is absent.
Then come back with a question: "how to pack my non-java resources into a jar, using XXX", where XXX will be the name of the techology you are using for building the jar.
Most probably the slash in "/hibernate.cgf.xml" is not needed, if the hibernate.cgf.xml is in the same package as you class HibernateUtil.
You can access the file actually also via the classloader using the full path. Yet you never add to it the first slash.
Here is some code demonstrating how you can access the file using different methods:
public static void main(String[] args) {
// Accessing via class
System.out.println(SimpleTests.class.getResource("hibernate.cgf.xml").getPath());
// Accessing via classloader from the current thread
String path = Thread.currentThread().getContextClassLoader()
.getResource("simple/hibernate.cgf.xml").getPath();
System.out.println(path);
// Accessing via classloader used by the current class
System.out.println(SimpleTests.class.getClassLoader().getResource("simple/hibernate.cgf.xml").getPath());
}
In the example above the package 'simple' should be replaced by the package where your hibernate.cgf.xml is. But you should never have the slash at the beginning of the package declaration.
This question already has answers here:
Reading a resource file from within jar
(15 answers)
Closed 6 years ago.
I built a game a while ago in eclipse. I wanted to export it like usual to a .jar. I've done this before and with my other projects it works. This one doesn't work because it gives a blank white screen. I put in a System.exit(1) on a different spots to see where the program stops working. Eventually I found the spot. It can't seem to locate my .txt file but in eclipse if does work. I've checked the .jar with 7zip(like winzip) and the .txt file is in there. I also used the command line to open it and it gives the same error of not being able to locate the .txt file. I've looked a lot on the internet and stackflow for people that have same questions of related problems but they didn't offer a fix unfortunately.
The code that make a new world is this.
world = new World(handler,"res/worlds/world1.txt");
In the world it calls this funtion:
loadWorld(path);
This funtion should return back a string. First it calls another function to get that string:
String file = Utils.loadFileAsString(path);
Finally this is the code that doesn't work because the file can't be located.
public static String loadFileAsString(String path){
StringBuilder builder = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
while((line = br.readLine()) != null)
builder.append(line + "\n");
br.close();
}catch(IOException e){
e.printStackTrace();
}
return builder.toString();
}
Is there something that I missed? Eclipse runs it fine but after exporting its like the .txt isn't exported but it is still there.
Thanks in advance.
The java class File (which is used by FileReader) operates on OS the file system path, either absolute, or relative to the current working directory. Your example denotes a relative path. I beg "res/world/..." is just beyond your project folder in eclipse. When running an app in eclipse the current directory is the project path itself. Therefore your code worked in eclipse.
Running standalone (by starting a jar) the file cannot be found in the same OS path. It is located within the jar. Therefore you must access it by using the resource loading features of your classloader.
That is a relative path. Relative paths are resolved relative to where you are when you execute the application. In eclipse this is, by default, the project directory. However, if you are running the jar externally, it will depend entirely on how you run the jar.
One common solution is to always have the jar placed in the same location relative to the resource (world1.txt). For example, the following directory structure...
-lib
--main.jar
-res
--worlds
---world1.txt
main.sh
Then, you need to get some base directory into your application. One way is to pass in the absolute path to main.jar as a command line argument, system property, or environment variable.
Another common approach is to get the path of the running jar file using some technique like this.
Finally, in your application, instead of using a relative path, you can use an absolute path:
String world1Path = baseDirectory + "res/worlds/world1.txt"
If you have an archive reader (such as 7zip) open up the .jar and see if your .txt file is inside the .jar. If not, simply copy the .txt file into the .jar file. This happened to me when trying to use a .png for a Java application. Hope it works out!
This question already has answers here:
How to read file from relative path in Java project? java.io.File cannot find the path specified
(15 answers)
Closed 6 years ago.
I have exported a project to a runnable JAR in eclipse. There are a few places in my code where I've done the following.
String file = "src/Files/...";
loadFile(file); // purely for example
Now that the project is in the form of a JAR, those directories don't seem to exist and loading those files fails. I'm pretty sure that the files I'm referencing are packed in the JAR. Do the directories change in any particular way when exported to JAR? Any other ideas on how to make this work?
You need to treat them as a classpath resource, not as a local disk file system path. This isn't going to work when you package the files in a JAR and you also don't want to be dependent on the working directory. Files inside a JAR are part of the classpath already.
Assuming that you've a foo.txt file in package com.example, then you can get an InputStream of it as follows
InputStream input = getClass().getResourceAsStream("/com/example/foo.txt");
// ...
Or when you're inside static context
InputStream input = SomeClass.class.getResourceAsStream("/com/example/foo.txt");
// ...
Or when you want to scan the global classpath
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("/com/example/foo.txt");
// ...
See also:
How to read file from relative path in Java project? java.io.File cannot find the path specified
getResourceAsStream() vs FileInputStream
I'm trying to have my application load a resource (binary file) transparently:
If the file exists under the current directory, open it.
If not, try looking in the current JAR file if applicable.
If not, try looking in other JAR files. (This is optional and I don't mind explicitly specifying which JAR files.)
So far I know of File which opens a local file and ClassLoader which has getResource* for JAR contents.
Is there a class which combines the two? If not, how should I go about writing it myself? Should I write a ClassLoader which also checks the local filesystem? Using File? (I'm very unfamiliar with Java and don't even know what's a good type to return. InputStream?)
Thanks
P.S. By "file" I mean "path", e.g. "data/texture1.png".
Doing #1 and #3 is pretty easy. Doing #2 (just looking in the current JAR only) is much harder as it requires you figuring out what JAR you
If you wanted to check the filesystem first, otherwise load from classpath, it would be something like:
public java.io.InputStream loadByName(String name) {
java.io.File f = new java.io.File(name);
if (f.isFile()) {
return new FileInputStream(f);
} else {
return getClass().getResource(name);
}
}
If you want to prefer loading from the same JAR file first, you will need to figure out where it is. Check out Determine which JAR file a class is from for more info on figuring out the JAR file you want to load the resource from.
A URLClassLoader should be able to load both and try the file path first if the file path is on the class path ahead of the jar.
Regarding your comments:
I know that relative jar URLs don't
work. That's why the Spring guys came
up with the Resource abstraction.
Read about it here.
You might want to check the answers
to this Question: Loading a file
relative to the executing jar
file. The problem is similar to
yours.
Current jar file and current directory are not concepts in the JVM like they are when you're running a shell script. You would need to specify a directory to be used for loading the files that you're interested in, such as with a system property while executing the JVM:
java -Ddirectory.to.scan=/home/aib
Then retrieve this property:
String dir = System.getProperty("directory.to.scan");
Now when talking about JAR files, all JAR files specified explicitly on the classpath when you start the JVM are loaded by the ClassLoader. You can get the ClassLoader of a specific class by:
InputStream is = <Your class>.class.getClassLoader().getResourceAsStream("binary file");
Note that any jar file loaded by the current class loader is searched.
I need to read a file in my code. It physically resides here:
C:\eclipseWorkspace\ProjectA\src\com\company\somePackage\MyFile.txt
I've put it in a source package so that when I create a runnable jar file (Export->Runnable JAR file) it gets included in the jar. Originally I had it in the project root (and also tried a normal sub folder), but the export wasn't including it in the jar.
If in my code I do:
File myFile = new File("com\\company\\somePackage\\MyFile.txt");
the jar file correctly locates the file, but running locally (Run As->Java Main application) throws a file not found exception because it expects it to be:
File myFile = new File("src\\com\\company\\somePackage\\MyFile.txt");
But this fails in my jar file. So my question is, how do I make this concept work for both running locally and in my jar file?
Use ClassLoader.getResourceAsStream or Class.getResourceAsStream. The main difference between the two is that the ClassLoader version always uses an "absolute" path (within the jar file or whatever) whereas the Class version is relative to the class itself, unless you prefix the path with /.
So if you have a class com.company.somePackage.SomeClass and com.company.other.AnyClass (within the same classloader as the resource) you could use:
SomeClass.class.getResourceAsStream("MyFile.txt")
or
AnyClass.class.getClassLoader()
.getResourceAsStream("com/company/somePackage/MyFile.txt");
or
AnyClass.class.getResourceAsStream("/com/company/somePackage/MyFile.txt");
If I have placed i file in a jar file, it only worked if and only if I used
...getResourceAsStream("com/company/somePackage/MyFile.txt")
If I used a File object it never worked. I got also the FileNotFound exception. Now, I stay with the InputStream object.