If you navigate to another directory and try to run your program with a different user.dir
, you also have to set the classpath. The error you get is because it can't find the class, not because it can't find the file.
Try
java -Duser.dir=c:/users/my/project -classpath c:/users/my/project MyClass
Regarding the user.dir
property, have a look at the documentation for the File
class. It states
A pathname, whether abstract or in string form, may be either absolute or relative. An absolute pathname is complete in that no other information is required in order to locate the file that it denotes. A relative pathname, in contrast, must be interpreted in terms of information taken from some other pathname. By default the classes in the java.io package always resolve relative pathnames against the current user directory. This directory is named by the system property user.dir
, and is typically the directory in which the Java virtual machine was invoked.
EDIT
I did a test on my machine and found that file reader looks in the directory that the application was launched from (which may not coincide with the user.dir
property). See below:
public static void main(String...args) {
try {
System.out.println("abs path to test.txt : " + new java.io.File("test.txt").getAbsolutePath());
System.out.println("user home : " + System.getProperty("user.home"));
System.out.println("user.dir : " + System.getProperty("user.dir"));
System.out.println("running from : " + new java.io.File(".").getAbsolutePath());
System.out.println(new java.io.BufferedReader(new java.io.FileReader("test.txt")).readLine());
} catch (Exception e) {
System.out.println("Not found");
}
}
Launching this from a directory that doesn't have the file in it I get
C:\Users>java -Duser.home=C:\Users\william -Duser.dir=C:\Users\william -classpath C:\Users\william\Desktop Test
abs path to test.txt : C:\Users\william\test.txt
user home : C:\Users\william
user.dir : C:\Users\william
running from : C:\Users\william\.
Not found
Whereas launching it from a directory that has the file I'm looking for I get
C:\Users\william>java -Duser.home=C:\Users\william -Duser.dir=C:\Users\william -classpath C:\Users\william\Desktop Test
abs path to test.txt : C:\Users\william\test.txt
user home : C:\Users\william
user.dir : C:\Users\william
running from : C:\Users\william\.
hello world
ANOTHER EDIT
I'm using the openjdk 8, so in my case the logic is as follows, from its source:
FileReader constructor with String
arg
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
FileInputStream constructors
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
FileInputStream open(String)
private void open(String name) throws FileNotFoundException {
open0(name);
}
The open0(String)
method is a native call (see below)
private native void open0(String name) throws FileNotFoundException;
Digging deeper, into the native call in FileInputStream.c
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
fileOpen(env, this, path, fis_fd, O_RDONLY);
}
Therefore the name
is what becomes the path
that the native fileOpen
method will use. This translates to file.getPath()
, which is different from file.getAbsolutePath()
.
file.getPath()
with file
as new File("test.txt")
returns test.txt
, which may not be found.
That's the best I can do, I hope it helps.
See this bug report and this question. In short, setting the user.dir via the command line is bad news.