2

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.

HHH
  • 6,085
  • 20
  • 92
  • 164
  • `/filename.txt` is an absolute path. Does `./filename.txt` work? – Ivan Nov 30 '15 at 19:39
  • Define the "root directory of your project". Is it on the classpath? – Dave Newton Nov 30 '15 at 19:41
  • @Ivan: no it is not working either. – HHH Nov 30 '15 at 19:42
  • @DaveNewton: No it is not, and I don't want to be. because what I'm gonna do is to use this piece of code in a hadoop job. This help me to package every dependency into my jar file and then ship. In HAdoop where the jar file gets copied is not always in the classpath – HHH Nov 30 '15 at 19:44
  • We really need to see the file structure of your project, and how you run this method from the command line. It all depends where this file really is. Can you provide a directory listing, or print the contents of the Jar file? – markspace Nov 30 '15 at 19:44
  • 1
    Did you check [How to really read text file from classpath in Java](http://stackoverflow.com/questions/1464291/how-to-really-read-text-file-from-classpath-in-java) or any other question related to `getResourcesAsStream` before asking? – Tobias Liefke Nov 30 '15 at 19:51
  • @H.Z. If it's not on the classpath then you can't load it as a resource :/ If you don't want the file on the classpath then you'll have to use a different mechanism. If it's in a jar file Hadoop is using then... it's pretty much on the classpath, otherwise Hadoop couldn't use anything *else* in the jar file either. – Dave Newton Nov 30 '15 at 20:38

5 Answers5

9

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().

Christian Semrau
  • 8,913
  • 2
  • 32
  • 39
  • Most build system will copy intermediate build files (like .class files) to a `build` directory, so it might help the OP to look there. Are all the files where the OP expects? – markspace Nov 30 '15 at 19:45
9

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.

pifta
  • 186
  • 6
  • yeah, I did not try that...:) sorry, fixed... :) – pifta Nov 30 '15 at 19:48
  • And did you try this one? `/` is no resource either... – Tobias Liefke Nov 30 '15 at 19:49
  • Good point. The OP could try something like `System.out.println(MyClass.getClass().getResource(MyClass.class.getName().replace('.','/')).getPath());` (not tested). – markspace Nov 30 '15 at 19:50
  • Tobias: I did, in Eclipse it gives me back the following: /C:/Users/username/workspace/project/bin/ – pifta Nov 30 '15 at 19:51
  • @markspace: for me your solution works after a few modifications this way `System.out.println(MyClass.class.getResource("/"+MyClass.class.getName().replace('.','/')+".class").getPath());` – pifta Nov 30 '15 at 19:59
  • 1
    @pifta Yeah, it needs those modifications or something similar, I kinda messed that up. Class loading is complicated! – markspace Nov 30 '15 at 20:03
  • @markspace never mind:) I was just curious, and made it work. – pifta Nov 30 '15 at 20:05
  • @pifta I guess you mean you started it for exactly one classes folder, and in that case it might work. But as soon as you have only JARs in the classpath or another kind of classloader (for example from a webapp) it will return `null`. – Tobias Liefke Nov 30 '15 at 20:18
2

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

Prim
  • 2,880
  • 2
  • 15
  • 29
  • 2
    If the program is NOT being run in a Jar file, then the classloader does search the file system for .class files (and resources like filename.txt). – markspace Nov 30 '15 at 19:43
  • that's right, I was running the program from Eclipse however my goal is to package it into a jar file and then run it. – HHH Nov 30 '15 at 19:57
1

user likewise,

InputStream sw = this.class.getClassLoader().getResourceAsStream("filename.txt");

Note : filename.txt file should be present on classpath.

Vishal Gajera
  • 4,137
  • 5
  • 28
  • 55
0

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)
markspace
  • 10,621
  • 3
  • 25
  • 39