Tip #13 java.io.File Surprises
- by ByronNevins
There is an assumption that I've seen in code many times that is totally wrong. And this assumption can easily bite you. The assumption is:
File.getAbsolutePath and getAbsoluteFile return paths that are not relative.
Not true! Sort of. At least not in the way many people would assume. All they do is make sure that the beginning of the path is absolute. The rest of the path can be loaded with relative path elements. What do you think the following code will print?
public class Main { public static void main(String[] args) { try { File f = new File("/temp/../temp/../temp/../"); File abs = f.getAbsoluteFile(); File parent = abs.getParentFile(); System.out.println("Exists: " + f.exists()); System.out.println("Absolute Path: " + abs); System.out.println("FileName: " + abs.getName()); System.out.printf("The Parent Directory of %s is %s\n", abs, parent); System.out.printf("The CANONICAL Parent Directory of CANONICAL %s is %s\n", abs, abs.getCanonicalFile().getParent()); System.out.printf("The CANONICAL Parent Directory of ABSOLUTE %s is %s\n", abs, parent.getCanonicalFile()); System.out.println("Canonical Path: " + f.getCanonicalPath()); } catch (IOException ex) { System.out.println("Got an exception: " + ex); } }}
Output:
Exists: trueAbsolute Path: D:\temp\..\temp\..\temp\..FileName: ..The Parent Directory of D:\temp\..\temp\..\temp\.. is D:\temp\..\temp\..\tempThe CANONICAL Parent Directory of CANONICAL D:\temp\..\temp\..\temp\.. is nullThe CANONICAL Parent Directory of ABSOLUTE D:\temp\..\temp\..\temp\.. is D:\tempCanonical Path: D:\
Notice how it says that the parent of d:\ is d:\temp !!!The file, f, is really the root directory. The parent is supposed to be null.
I learned about this the hard way! getParentXXX simply hacks off the final item in the path. You can get totally unexpected results like the above. Easily.
I filed a bug on this behavior a few years ago[1].
Recommendations:
(1) Use getCanonical instead of getAbsolute. There is a 1:1 mapping of files and canonical filenames. I.e each file has one and only one canonical filename and it will definitely not have relative path elements in it. There are an infinite number of absolute paths for each file.
(2) To get the parent file for File f do the following instead of getParentFile:
File parent = new File(f, "..");
[1] http://bt2ws.central.sun.com/CrPrint?id=6687287