When I run a Java application that should be reading from a file in Eclipse, I get a java.io.FileNotFoundException, even though the file is in the correct directory. I can compile and run the application from the command line just fine; the problem only occurs in Eclipse, with more than one project and application. Is there a setting I need to change in the run configurations or build paths to get it to find the file correctly?

6 Answers
6

The problem is most likely that your application is using a relative pathname. As @BalusC says, relative pathnames can be problematic. But IMO, he goes way too far when he says "[y]ou should never use relative paths in java.io stuff".

When an application opens a file using (for example) the FileInputStream(File) constructor, relative pathnames are resolved relative to the "current directory" in a process described as follows in the javadoc for File.getAbsolutePath().

[...] Otherwise this pathname is resolved in a system-dependent way. On UNIX systems, a relative pathname is made absolute by resolving it against the current user directory. On Microsoft Windows systems, a relative pathname is made absolute by resolving it against the current directory of the drive named by the pathname, if any; if not, it is resolved against the current user directory.

So immediately, we see that the notion of "current directory" has different nuances on Windows and UNIX platforms. The second issue is that in pure Java you cannot definitively find out what the current directory is, and you certainly cannot change it for the current JVM using pure Java. (When the JVM starts, the "user.dir" system property is set to the current directory, but there is nothing stopping an application from changing the property so you cannot entirely rely on it. Furthermore, changing "user.dir" only changes the way that the empty path is resolved, not relative paths in general.)

So what should you do about this?

One option is to use absolute pathnames to refer to files. This is reliable in (almost) all cases, but using absolute pathnames can be problematic if the user has to enter the pathname, or
if you need to avoid hard-wired (or configured) absolute pathnames.

A second option is to use classpath relative pathnames and locate files relative to the application's installation directory. This works if that is what you need to do, but presents a problem if you need to pass a File to some library method. It also doesn't help if you are trying to find the user's application preferences. (In general, putting user preferences into the installation directory is a mistake ...)

A third option is to name a file relative to some absolute directory that you get from somewhere else; e.g. new File(System.getProperty("home.dir"), "foo/bar");.

The final option is to use relative pathnames, and assume that the user knowing what the current directory. For many applications that the user runs from the command line, this is the right solution.

In the particular case of Eclipse, there is a simple solution. Go to the "run configuration" that you are using to launch your application, open the "Arguments" tab, and click the "Other" radio button. Then enter an absolute pathname as the working directory for the launched application. When the child JVM is launched, it will have the specified working directory as its current directory.

Had a problem with my app launched from eclipse not being able to read some properties file which was in the root of my project. After I tried setting the working directory in run configuration to ${workspace_loc}/myproject/bin it worked!.
–
KrishnarajNov 8 '12 at 18:16

@Krishnaraj - That's what I said in the last paragraph of my answer :-)
–
Stephen CNov 8 '12 at 22:41

If your application requests "./data.txt" it will search for it relative to the root directory. This is the "working directory" and can be configured in the arguments tab as per Martin's reply above.

You say it works from the command line? This is likely because you're inside either the bin or src folders when you run the java binary. The working directory in this case is whichever directory the command prompt is currently inside. If, for example, you go into the /src/ directory, say javac *.java then run the files from there, it will search for "./data.txt" within the /src/ directory. If you go inside the /bin/ directory and run your application from there, it will look for the file relative to the /bin/ directory.

Thanks for your help. The text files I need do exist in the /bin/ directory, so that doesn't seem to be the problem. I'll play around with relative paths and see what I can get.
–
derekerdmannMay 8 '10 at 4:26

You should never use relative paths in java.io stuff. The path would become dependent on the current working directory, which depends on the way how you started the application and is thus not per se the same on all environments. This is uncontrollable from inside the Java application. Portability trouble! Always use absolute paths. Thus e.g. c:/path/to/file.ext or /path/to/file.ext (with the leading slash) for UNIX and consorts (or even Windows when the disk letter is irrelevant).

Whenever you'd like to ship some files along with your application, a common practice is to place them in the classpath as well. This way you can just use ClassLoader#getResource() to get its location. It returns an URL. You can use URL#toURI() or URL#getPath() and pass it to constructor of java.io.File and then use it further the usual way.

In your Eclipse project, the src folder (where your Java source goes) is basically the root of the classpath. Further it of course also covers all other projects and (external) folders which are taken in the project's Build Path.

Assuming that you've placed the particular file in the root of the classpath:

a non-GUI command line application can reasonably be designed to use relative pathnames. The caveat is that the user needs to understand the concept of "the current directory", and the programmer needs to understand how this maps to the behavior of the Java IO libraries.
–
Stephen CMay 8 '10 at 5:14

@Stephen: It is surely possible, you'll only have to hassle with relative paths, but it is not recommended. Taking benefit of the classpath makes it more robust.
–
BalusCMay 8 '10 at 5:18

it depends on what the application is doing. For example, if it is manipulating files supplied by the user, then the classpath approach makes little sense.
–
Stephen CMay 8 '10 at 5:57

@Stephen: Which is thus not the case in the original question :)
–
BalusCMay 8 '10 at 6:26

1

but IS the case in the context of your answer - "You should never use relative paths in java.io stuff."
–
Stephen CMay 8 '10 at 7:04

I was having a similar problem , I placed my files in a folder named cobolcopybooks inside the src folder and tried to access them inside my project using classloader.getResource("cobolcopybooks/demostud.cob")
but i was getting null pointer exception,i tried it several times by cleaning and building the workspaces after several failed attempts i realised that i was not refreshing the project to allow the files to get built along with the project. i.e these files should be visible along with other class files as at runtime the root directory will be bin directory and it's searching for those files there.

Another option is to simply figure out what directory the "current path" points to in your environment -- whatever that is. Once you figure out, you can choose your solution from there. Maybe that is to use an appropriate relative path to your file's location or relocating the file.

Assuming the user does not enter the full file path to the file
and enter something like "myfilenameonly".
File file = new File(".", args[0]) is necessary in this case to
locate the file (paying attention to the first argument passed).

All platforms: File.getParent() does not return the parent directory,
it should return ".." or the name of the parent directory in a file-system
specific way.

If you create the File "myfilenameonly" without specifying the full path
to the directory where it is located, the File.getParent(), for example,
will return null.