Java Programming Language

OracleブログにJavaプログラミングに関するちょっとしたティップが「Tip #13 java.io.File Surprises (Byron Nevins)」として掲載されている。java.io.Fileの絶対パスに関する扱いが勘違いしやすいものだから注意するように、といった内容になっている。

掲載されているサンプルソールコードを若干アレンジしたものを次に掲載する。

import java.io.*;


public class Demo
{
    public static void main(String[] args)
    {
        try 
        {
            String path = "/tmp/../tmp/../tmp/../";
            File abspath = new File(path).getAbsoluteFile();
            File canpath = new File(path).getCanonicalFile();
            File abspathpare = abspath.getParentFile();
            File canpathpare = canpath.getParentFile();
            System.out.println("調査対象: " + path);
            System.out.println("絶対パス: " + abspath);
            System.out.println("正規パス: " + canpath);
            System.out.println("絶対パスのファイルは存在するか: " + abspath.exists());
            System.out.println("絶対パスのファイル名: " + abspath.getName());
            System.out.println("絶対パスの親ディレクトリ: " + abspathpare);
            System.out.println("正規パスの親ディレクトリ: " + canpathpare);
            System.out.println("絶対パスの親ディレクトリの正規パス: " + abspathpare.getCanonicalPath());
        } 
        catch (IOException ex) 
        {
            System.out.println(ex);
        }
    }
}

これをビルドして実行すると次の結果を得る(OpenJDK 7.0.147 on FreeBSD 10-CURRENT)。

% java Demo
調査対象: /tmp/../tmp/../tmp/../
絶対パス: /tmp/../tmp/../tmp/..
正規パス: /
絶対パスのファイルは存在するか: true
絶対パスのファイル名: ..
絶対パスの親ディレクトリ: /tmp/../tmp/../tmp
正規パスの親ディレクトリ: null
絶対パスの親ディレクトリの正規パス: /tmp
%

サンプルの実行結果からわかるように、getAbsolute*()によって取得されるパスは正規パス(canonical path)ではない。getAbsoluteFile()によって得られる結果が正規パスになっていると仮定してコーディングを実施すると想定と違う動きをする。サンプルに掲載されているパス表記はその良い例と言える。紹介記事ではこうしたコーディングの誤りはよく見られるものだと指摘し、getAbsolute*()系ではなくgetCanonical*()系を使うことを推奨している。