File.getAbsolutePath と getAbsoluteFile は相対でないパスを返す正しくないのですよ。ちょっとね。少なくとも、多くの人が考えている通りではありません。
パスの最初が絶対パスで、パスの残りの部分に相対パスの要素を指定してみましょう。
以下のコードではどのような結果を出すと思いますか?
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);
}
}
}
実行してみると…[訳注]Exists: true Absolute Path: D:\temp\..\temp\..\temp\.. FileName: .. The Parent Directory of D:\temp\..\temp\..\temp\.. is D:\temp\..\temp\..\temp The CANONICAL Parent Directory of CANONICAL D:\temp\..\temp\..\temp\.. is null The CANONICAL Parent Directory of ABSOLUTE D:\temp\..\temp\..\temp\.. is D:\temp Canonical Path: D:\
実行環境によってルートディレクトリは異なります。
d:\の親はd:\tempと言っていることに注目して下さい。ファイルfは実際にはルートディレクトリですので、本当なら親はnullになるはずです。私はようやくこのことがわかりました。getParentXXX()は単にパスの最後の部分を切り取るだけなのです。上記のような全く予期しない結果が簡単に出るのです。
実はこの振る舞いは、数年前にバグ登録しています。
http://bt2ws.central.sun.com/CrPrint?id=6687287
推奨策
(1) getAbsoluteではなく、getCanonicalを使うと、ファイルとカノニカルファイル名を1:1に対応します。つまり、各ファイルには唯一のカノニカルファイル名がありますが、ファイル名中のパス要素とは明確な関連がありません。各ファイルの絶対パスは無数に存在します。
(2) File fの親ファイルを取得するためには、getParentFile()を使わずに以下のような方法を使いましょう。
File parent = new File(f, "..");
原文はこちら。
http://blogs.oracle.com/foo/entry/tip_13_java_io_file
0 件のコメント:
コメントを投稿