Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java two dots at the end of a path have unexpected results

Tags:

java

windows

I've run into what I thought was unusual behavior when working with some File objects.

import java.io.File;

public class MyClass
{
    public static void main(String[] args)
    {
        File file = new File("C:\\x..");

        System.out.println(file.isDirectory());

        System.out.println(file.listFiles());
    }
}

Assuming that some directory C:\x exists, file.isDirectory() will return true with the added two dots at the end of the path. This replicates the behavior in the command line, where cd x.. will change the directory to x.

However, when calling file.listFiles(), the method returns null, which is only supposed to happen if the file is not a directory. This seems to be inconsistent with the definition of the listFiles().

Why is this so? And why does having two dots at the end of the path go to the same directory as if there was no dots?

This problem seems to be exclusive to Windows. Linux correctly (?) returns false for isDirectory().

like image 438
Kat Avatar asked Jan 17 '26 00:01

Kat


1 Answers

Windows trims trailing dots from path and filenames. I am unable to find a concrete reference for this, it's just one of those mysterious things that has always been that way.

It trims the trailing dots from the full pathname, not the individual components.

Therefore, while "C:\x...." is the same as "C:\x", "C:\x....\filename" is not the same as "C:\x\filename", as the latter does not have trailing dots.

You would have to look at the JDK's native FileSystem source on Windows to see precisely how it is obtaining a list of files, but I suspect it's doing some kind of search on e.g. "C:\x..\*.*" using Windows' FindFirstFile API call or something, where the dots are no longer trailing. In other words, presuming "C:\x" is a directory, while the path "C:\x.." is a directory, "C:\x..\*.*" matches nothing, and "C:\x..\subdirectory" does not map to "C:\x\subdirectory".

You should avoid using such paths. I'm not sure how you obtained that path string in the first place.

You can use File.getCanonicalPath() or File.getCanonicalFile() to convert it back to a more useable pathname.

By the way, if you want to have some fun with Windows, type the following in a command prompt (assuming "c:\windows\temp" exists, otherwise replace with some other path):

echo > \\?\c:\windows\temp\x.

The \\?\ prefix in Windows disables filename processing and expansion. Now delete the resulting file. Try it in Explorer too.

Spoiler:

You'll have to delete it with a wildcard from the console, e.g. del x?

like image 74
Jason C Avatar answered Jan 19 '26 12:01

Jason C



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!