java.io.File.<init>(File,String) JDK version dependent [duplicate]

  • A+
Category:Languages

This question already has an answer here:

It's looks like java.io.File.(File, String) is JDK version dependent. Code example was run on Windows 10.

Code example:

public static void main(String... args) {     String path = "C://Workspace//project";     File file = null;     for (String part : path.split("////")) {         file = new File(file, part);     }     System.out.println(file);     // prints "C:Workspace/project" for JDK 9+     // prints "C:/Workspace/project" for JDK 8 } 

Could you please address is there any known issue or solution for the case

 


In Java 9, the WinNTFileSystem class (FileSystem implementation for windows) changed.
It probably solves a issue which the way the class considers what a absolute path is. I didn't find a bug that exactly specifies this one but some are close to.

File.isAbsolute() states :

On Microsoft Windows systems, a pathname is absolute if its prefix is a drive specifier followed by "/", or if its prefix is "//".

So according to the specification, for the following:

File x = new File("C:", "Workspace");  System.out.println(x.isAbsolute()); // not absolute according to the spec  File xx = new File("C://", "Workspace"); System.out.println(xx.isAbsolute());  File xxx = new File("////Workspace"); System.out.println(xxx.isAbsolute()); 

we expect :

false true true

But we get :

true true true

From Java 9 it produces the expected result.

The problem is that before Java 9 a path without / is all the same considered as an absolute path :

File x = new File("C:", "Workspace"); System.out.println(x.isAbsolute()); // true 

While that this should not be the case.

Concretely, the main changes concern the resolve(String parent, String child) method of the WinNTFileSystem class.
Before, resolve() resolved the abstract path by adding a slash between the parent and the child for any child path that doesn't start with a slash.
From Java 9, resolve() doesn't add a slash any longer between the parent and the child if the parent is a drive.

Here is the change :

boolean isDirectoryRelative =     pn == 2 && isLetter(parent.charAt(0)) && parent.charAt(1) == ':';  if (child.charAt(childStart) == slash || isDirectoryRelative) {     theChars = new char[strlen];             ^-------- this one was added from Java 9     parent.getChars(0, parentEnd, theChars, 0);     child.getChars(childStart, cn, theChars, parentEnd); } else {     theChars = new char[strlen + 1];     parent.getChars(0, parentEnd, theChars, 0);     theChars[parentEnd] = slash;     child.getChars(childStart, cn, theChars, parentEnd + 1); } 

Consequences

About your question :

Could you please address is there any known issue or solution for the case

The difference between the two JDK versions matters. It concerns both the value of the abstract pathname's normalized pathname (File.getPath()) and the value of the absolute path File.getAbsolutePath() as now new File("C:", "Workspace") produces a relative path.

If your application relies on File.getPath() to do some parsing on that, it could have a distinct behavior and create some issues.
To have a portable code between the JDK versions, any parsing on the resolved path should consider as optional the / just after the Windows drive.
In this way C:/ and C: would be handled in the same way.

If your application relies on File.getAbsolutePath(), it could also have some surprises from Java 9 as now the path that is relative will be resolved against the filesystem (before as an absolute path this just returned itself).
So instead, you should so probably use File.getPath() to not resolve the path against the file system.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: