Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java : File.exists() inconsistencies when setting "user.dir"

JRE 6, on Windows XP.

Instanciating two File objects with different constructors leads to inconsistent results in the File.exists() method.

Disclaimer : the code below is an abstract, not the actual code. I do not believe this is a File.separator issue at all. I first asked to get early reactions, in case I missed a well understood issue. It now seems that resetting the user.dir system property is one of the causes to this problem. The code below is now reproducible and usable as is. You can copy/paste the Java class and try it, it should behave consistently with what I have listed as results.

Setup:

Create the folder architecture C:\toto\tmp\sub.

Launch the following class from within any folder which does not contain a tmp/sub sub-folder architecture.

Code:

public class TestFileExists {

    public static void main(String[] args) {

        System.setProperty("user.dir", "C:\\toto\\");

        File root = new File("tmp");

        File sub_a = new File(root, "sub");

        File sub_b = new File(root.getAbsolutePath()+"/sub");

        System.out.println("sub_a path ? "+sub_a.getAbsolutePath());
        System.out.println("sub_a exists ? "+sub_a.exists());
        System.out.println("sub_b path ? "+sub_b.getAbsolutePath());
        System.out.println("sub_b exists ? "+sub_b.exists());
        System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath())));
        System.out.println("Obj equals ? "+ (sub_a.equals(sub_b)));

    }

}

Result :

sub_a path ? C:\toto\tmp\sub
sub_a exists ? false
sub_b path ? C:\toto\tmp\sub
sub_b exists ? true
Path equals ? true
Obj equals ? false

I don't understand the line sub_a exists ? false, and the result is not consistent from machine to machine, nor with the root initial path ant the result is now consistent with from machine to machine.

Now if you reexecute the class by calling java from the command line, from a folder which does contain a tmp/sub sub-folder architecture (like if you call it from D:\, having D:\tmp\sub), you will get the expected :

sub_a path ? C:\toto\tmp\sub
sub_a exists ? true
sub_b path ? C:\toto\tmp\sub
sub_b exists ? true
Path equals ? true
Obj equals ? false

But the existence of sub_a is clearly a false positive, because it checks the existence of another folder than the one described by the getAbsolutePath().

So I strongly suspect that File.exists() depends on the actual Java execution path, and that file existence is not consistent with the absolute path, and exists() uses another path than the "user.dir" system property to check the file system.

Any idea where this problem could come from ?

like image 839
glmxndr Avatar asked Feb 16 '10 18:02

glmxndr


3 Answers

Setting user.dir is unsupported. It should be considered a read-only property.

For example the evaluation of Bug 4117557 in the Sun Bug Parade contains this text:

"user.dir", which is initialized during jvm startup, should be used as an informative/readonly system property, try to customize it via command line -Duser.dir=xyz will end up at implementation dependend/unspecified behavior.

While this text is about setting it on the command line, setting it via setProperty() is most likely equally undefined.

When you can reproduce the problem without setting user.dir manually, then you've found a genuine problem.

like image 175
Joachim Sauer Avatar answered Oct 19 '22 06:10

Joachim Sauer


Add the following lines to your test:

System.out.println("sub_a = " + sub_a);
System.out.println("sub_b = " + sub_b);

Conclusions:

1) sub_a is a relative path and sub_b is an absolute one.

2) exists() does not use the absolute path

3) setting the environment variable user.dir does not change the current user directory, used by exists()

4) getAbsolutePath uses the user.dir variable instead of the real current user directory! At least for Windows (see Win32FileSystem.getuserPath). That's the problem! (Bug?)

like image 28
user85421 Avatar answered Oct 19 '22 06:10

user85421


File can represents an abstract path. Creating a File for tmp and one from the absolute path of tmp will not be equal File objects though their absolute paths are equal.

I'm not exactly sure of a scenario where sub_a won't exist but sub_b will but i doubt it's a separator issue. I suspect it's something to do with this statement from the javadoc for File(File,String):

each pathname string is converted into an abstract pathname and the child abstract pathname is resolved against the parent.

I don't know a situation on Unix-based file systems where, from within /full/path/to, ./tmp/sub will exist but /full/path/to/tmp will not.

If the problem is consistent between systems, it can be understood more clearly by dumping more of each File object's state instead of just printing comparisons.

like image 29
nicerobot Avatar answered Oct 19 '22 06:10

nicerobot