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?
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.
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.
File testFile = new File("");
String currentPath = testFile.getAbsolutePath();
System.out.println("current path is: " + currentPath);
When you create a default Java application in Eclipse, you get this directory structure:
./ProjectName/ - root directory
./ProjectName/bin/ - output directory, containing .class files
./ProjectName/src/ - source directory, containing .java files
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.
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.
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.
See further: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537
Related
The file’s getAbsolutePath has the tendency that if a relative path or just the file name is provided in the file constructor, then it will resolve the absolute path by prefixing the current working directory.
The definition of current working directory is the directory where we run our Java Program.
In my example, my java program resides inside D:\my-app\src\App.java
When I do a System.out.println(System.getProperty("user.dir"));
Then it should ideally print D:\my-app\src
But it is actually printing D:\my-app
Why is it so?
When you start an application from IntelliJ, its working directory is set according to what's set in "Working directory" in the "Run/Debug Configurations" dialog.
There, you can set the working directory to a fixed value such as D:\my-app\src. Another option is to use a path variable. The list of variables that are available apparently can depend on many things - open the dialog and see what's available. One option that I see is $FileDir$ which I imagine would be the directory of the source code file.
I think I found the solution. Intellij was actually causing the issue by implicitly setting the src folder as the source folder. I found it by going to the module setting within Intellij.
When I ran the same from a command prompt, the correct working directory i.e. D:\my-app\src\ is selected.
I am developing a program that uses a sqlite file as a database. When I compile and test my program I haven't any problem:
Conection c = DriverManager.getConnection(
"jdbc:sqlite:/home/mehdi/my_database.sqite");
as you can see in above, the code shows a direct path that set to database file (this path is only in my system).
So it works fine, but my problem starts when I create an executable jar file of my program, if I create executable jar file and share it with other users, when they run the executable jar it doesn't work.
My first question: how do I set my database path for an executable jar file in my code?
My second question: is it possible for the database to be along side the executable jar? (and i can move my executable jar file with its database)
some_path/my_program_file.jar
some_path/my_database.sqite
The best option is externalizing the database path instead of hardcoding it, and letting the user choose where to put the actual sqlite file.
You could put the sqlite file in the same directory as the program archive, but please note that this does not really help in locating the file from your code, because relative paths are definitely resolved against the JVM (process) working directory, not the location of the JAR:
new File(".").getAbsolutePath()
There are ways to get the location of the JAR:
getClass().getProtectionDomain().getCodeSource().getLocation()
but they are deploy-dependent, so it's not a very robust strategy to rely on.
Most Java program are configured with external files put in well-known locations (like the current JVM directory or a .myapp/conf.properties in the user home), and individual properties can be overridden in the starting command line, as either system properties -Dkey=value or program arguments (there's a library to simplify this)
Java uses relative paths when you do not specify the absolute path. I'm not sure if it works for the DriverManager though. What this means is that if you call jdbc:sqlite:my_database.sqite it should look for my_database.sqite in the folder the jar is executed from. So if the user calls java -jar my_program_file.jar from the folder where the database is it will work. If the user calls the jar from another location it won't. To fix that, you have to grab the path where the jar is located, like so:
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
This was showcased in another SO post.
I wrote desktop program in Java on Windows 7 and hanged it on startup by writing to registry the path of jar file (kind of C:\Users\User\Documents\My App.jar) in HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Run branch. When my program loads with Windows, it must load some text file that placed in the same folder as the program:
File f = new File("text.txt"); // without full path to file
if(!f.exists())
JOptionPane.showMessageDialog(null, "File not found: " + f.getAbsolutePath());
but cant do it and I get message: "File not found: C:\Windows\system32\text.txt". It appears as if the program is located in the system32 folder and a text file, respectively, too. What did I do wrong?
My theory: if you installed Java for Windows via the traditional installer, in addition to the place you told it to put it (canonically, JAVA_HOME), the installer drops a java.exe in the system32 directory, so it's likely that when you're starting the JVM on startup, system32 is the working directory and that's where it will look for files with relative path names like the one you've provided.
The easiest solution is to specify the path to the text file absolutely in your code. I would also recommend specifying the full path to java.exe in your registry key (I would guess that right now it's just java.exe with no path) so that you can guarantee which version you're running; if you have multiple versions of Java installed only the most recently one installed will have java.exe in system32 and without a qualifying path I would guess that's the one you're getting since PATH will probably be minimal at that point.
As a closing--unrelated to your problem--point, I hate that Java does this on Windows and wipe that copy of java.exe out immediately, and then set up PATH to make sure the version I want is the one that is executed on demand.
You need to get current working directory and use it as a part of absolute path to a file.
Take a look at this question: Getting the Current Working Directory in Java
The other workaround would be to read this registry key you described and using this information to read a file from desired path - read/write to Windows Registry using Java
The path that you are referring is the working directory, and is not where the application is installed. Like if you put a shorcut to it, you can change the working directory and it will change the result you are getting. But as you put it to startup automatically, probably windows is setting this as the working directory.
Like that:
Use registry to startup a program, and also change the current working directory? 1
You can try to pass the file directory to your app with a command line parameter in the registry.
1 - This probably won't solve the problem for you, don't seems you have one, its just an explanation
I think that #Omaha's answer is describing what is going on (you are launching java.exe from the system32 directory - the JRE installer places a copy of java.exe in system32 to make it easier for users to access).
The actual solution to your situation is to adjust your CurrentVersion\Run registry entry so it specifies a default working folder for the application. Check out: Use registry to startup a program, and also change the current working directory?
Im looking for a solution to create a new folder in the folder, where the .jar file is located.
So if i have a test.jer file in C:\test\temp I would like to be able to create a new folder (newFolder) : C:\test\temp\newFolder.
Anyone know how to do this.
I have tried to use
System.getProperty("user.dir").
But this only gives me the correct, if i double click the jar file.
I need it to be run from a scheduler and then the location is changed.
In general you cannot easily figure out where your JAR file is at runtime. The execution environment of your VM can tell you the user directory (as you said), but that is the directory from which the VM was started. So if you double click your JAR, that's actually the directory where the JAR is. But if you call java on the commandline, for example
c:\some\directory> java -cp c:\temp\test.jar main.Class
then "user.dir" will contain "c:\some\directory".
This lack of information is intentional, because it allows the VM to transparently load classes from different locations.
Your best choice to do what you want would be to pass the directory of choice as a commandline argument. And in the worst case, you could use "user.dir" as default. But what the best solution really is depends on why you want to place the directory where the JAR is.
My file is located under the src directory. However, when I try to call it using "src/readme.txt" the file is not found.
In fact, it states that java is looking for "C:\Documents and settings\john\My Documents\Downloads\eclipse-win32\eclipse\coolCarsProject\src\readme.txt".
How do I fix this? I do not want to put in the absolute path all the time.
Do I need to fix the classpath, buildpath, or change the project root, etc? It is not at all obvious from the roughly 1000 settings in Eclipse for a newbie.
First, you have to decide if you want to load the file from the file system, or if the file will in fact be bundled with your application code.
If the former, then you should really think about how your application will be launched when actually deployed, because using a relative file path means that the program should always be started from the same location: a relative path is relative to the location from where the program is started (the current directory). If this is really what you want, then edit your launch configuration in Eclipse, go to the Arguments tab, and set the working directory you want. But the src directory is not where you should put this file, since this will copy the file to the target directory, along with the classes, that will probably be put in a jar once you'll deploy the application.
If the latter, then you should not treat the file as a file, but as a resource that is loaded by the ClassLoader, using ClassLoader.getResourceAsStream() (or Class.getResourceAsStream()). Read the javadoc of those methods to understand the path to pass. If you put the file directly under src, it will be copied by Eclipse to the target directory, along with your classes, in the default package. And you should thus use SomeClass.class.getResourceAsStream("/readme.txt") to load it.
Using paths relative to the current working directory is not a good idea in general, as it's often quite hard to establish what your current working directory will be. In Eclipse, it will be your project folder (unless you set it to something different in your launch configuration), in webapps it will be the webapp's root directory, in a command line app it could be anything.
Try this one:
String filePath = ".\\userFiles\\data.json";
where «.\» is a root for the Eclipse project, «userFiles» is a folder with the user's files inside of Eclipse project. Since we are talking about Windows OS, we have to use «\» and not «/» like in Linux, but the «\» is the reserved symbol, so we have to type «\\» (double backslash) to get the desired result.