Path
クラスには、パスに関する情報の取得、パスの要素へのアクセス、パスの他の形式への変換、またはパスの内容の抽出に使用できるさまざまなメソッドが含まれています。 また、パス文字列を照合するためのメソッドや、パスの冗長部分を削除するためのメソッドもあります。 このレッスンでは、これらのPath
メソッドについて取り上げます。Path
メソッドはパス自体を操作し、ファイル・システムにはアクセスしないため、統語処理と呼ばれることもあります。
このセクションでは次の内容について説明します。
Path
インスタンスには、ファイルまたはディレクトリの場所を示す情報が含まれます。 この情報は、Path
を定義するときに、1つ以上のファイル名またはディレクトリ名を続けた文字列を引数として指定します。 この文字列にはルート要素とファイル名を含めることができますが、どちらも必須ではありません。 また、Path
は単一のディレクトリ名またはファイル名のみで構成される場合もあります。
Path
オブジェクトは、Paths
(複数形であることに注意してください)ヘルパー・クラスにあるget
メソッドのいずれかを使用して簡単に作成できます。
Path p1 = Paths.get("/tmp/foo"); Path p2 = Paths.get(args[0]); Path p3 = Paths.get(URI.create("file:///Users/joe/FileTest.java"));
Paths.get
メソッドは、次のコードの省略表現です。
Path p4 = FileSystems.getDefault().getPath("/users/sally");
次のコードでは、ホーム・ディレクトリが/u/joe
であるとすると、/u/joe/logs/foo.log
(Windowsの場合はC:\joe\log\foo.log
)が作成されます。
Path p5 = Paths.get(System.getProperty("user.home"), "logs", "foo.log");
Path
は、名前要素を1つのシーケンスとして保存するものと考えることができます。 ディレクトリ構造内の最上位要素はインデックス0で表され、ディレクトリ構造内の最下位要素はインデックス[n-1]
(n
はPath
内の名前要素の個数)となります。 このインデックスを使用してPath
の個別要素またはサブシーケンスを取得するメソッドが用意されています。
このレッスンで取り上げるサンプルでは、次のディレクトリ構造を使用します。
次のコードでは、Path
インスタンスを定義し、いくつかのメソッドを呼び出して、パスに関する情報を取得しています。
// 次のメソッドはいずれも、Pathに対応するファイルが存在している // 必要はありません。 Path path = Paths.get("C:\\home\\joe\\foo"); // Microsoft Windowの構文 //Path path = Paths.get("/home/joe/foo"); // Solarisの構文 System.out.format("toString: %s%n", path.toString()); System.out.format("getFileName: %s%n", path.getFileName()); System.out.format("getName(0): %s%n", path.getName(0)); System.out.format("getNameCount: %d%n", path.getNameCount()); System.out.format("subpath(0,2): %s%n", path.subpath(0,2)); System.out.format("getParent: %s%n", path.getParent()); System.out.format("getRoot: %s%n", path.getRoot());
呼び出したメソッド | Solaris OSでの出力結果 | Microsoft Windowsでの出力結果 | 説明 |
---|---|---|---|
toString |
/home/joe/foo |
|
Path の文字列表現が返されます。 対象のパスがFilesystems.getDefault().getPath(String) または(getPath の簡易版メソッドである)Paths.get を使用して作成されたものである場合は、このメソッドにより、パス文字列の簡単な正規化が行われます。 たとえば、UNIXオペレーティング・システムでは、//home/joe/foo という入力文字列は/home/joe/foo に修正されます。
|
getFileName |
foo |
foo |
ファイル名、または名前要素シーケンスの最後の要素が返されます。 |
getName(0) |
home |
home |
指定したインデックスに対応するパス要素が返されます。 0番目の要素はルートにもっとも近いパス要素です。 |
getNameCount |
3 |
3 |
パス内の要素数が返されます。 |
subpath(0,2) |
home/joe |
home\joe |
開始インデックスと終了インデックスで指定したPath のサブシーケンス(ルート要素は含まない)が返されます。
|
getParent |
/home/joe |
\home\joe |
親ディレクトリのパスが返されます。 |
getRoot |
/ |
C:\ |
パスのルートが返されます。 |
上のサンプル・コードは、絶対パスの出力について表しています。 次に示すコードでは、相対パスを指定します。
Path path = Paths.get("sally/bar"); // Solarisの構文 または Path path = Paths.get("sally\\bar"); // Microsoft Windowsの構文
WindowsとSolaris OSにおける出力結果は次のとおりです。
呼び出したメソッド | Solaris OSでの出力結果 | Microsoft Windowsでの出力結果 |
---|---|---|
toString |
sally/bar |
sally\bar |
getFileName |
bar |
bar |
getName(0) |
sally |
sally |
getNameCount |
2 |
2 |
subpath(0,1) |
sally |
sally |
getParent |
sally |
sally |
getRoot |
null |
null |
Path
に冗長なディレクトリ情報が含まれる可能性があります。 たとえば、サーバーが"/dir/logs/.
"ディレクトリにログ・ファイルを保存するように設定されている場合に、パスの末尾の"/.
"を削除したいと考えるかもしれません。
次のパスには両方とも、冗長な表現が含まれています。
/home/./joe/foo /home/sally/../joe/foo
normalize
メソッドを使用すると、".
"や"ディレクトリ名/..
"などの冗長な要素が削除されます。 上のパスはいずれも、/home/joe/foo
に正規化されます。
normalize
では、パスの冗長部分を削除する際にファイル・システムの実際の状況が確認されるわけではないことに注意してください。 これは純粋な統語処理です。 上の2つ目のパスでsally
がシンボリック・リンクの場合、sally/..
を削除すると、Path
が目的のファイルの場所を示さなくなる可能性があります。
パスの冗長部分を削除し、かつ、正しいファイルの場所が確実に示されるようにするには、toRealPath
メソッドを使用できます。 このメソッドについては、次のセクションのパスの変換で説明します。
Path
の変換に使用できるメソッドは3つあります。 パスを、ブラウザから開くことのできる文字列に変換する必要がある場合は、toUri
を使用できます。 次のように使用します。
Path p1 = Paths.get("/home/logfile"); System.out.format("%s%n", p1.toUri()); // 結果はfile:///home/logfile
toAbsolutePath
メソッドは、引数のパスを絶対パスに変換します。 引数のパスがすでに絶対パスの場合は、同じPath
オブジェクトが返されます。 toAbsolutePath
メソッドは、ユーザーが入力したファイル名を処理する際に非常に便利です。 次のように使用します。
public class FileTest { public static void main(String[] args) throws IOException { if (args.length < 1) { System.out.println("usage: FileTest file"); System.exit(-1); } // 入力文字列をPathオブジェクトに変換します。 Path inputPath = Paths.get(args[0]); // 入力Pathを絶対パスに変換します。 // 通常はこの変換によって、パスの先頭に現在の作業ディレクトリが追加されます。 // このサンプル・プログラムが次のように呼び出されるとします。 // java FileTest foo // この場合、"inputPath"インスタンスのgetRootとgetParentの各メソッドでは // nullが返されます。絶対パスに変換した"fullPath"インスタンスの // getRootとgetParentでは、期待した値が返されます。 Path fullPath = inputPath.toAbsolutePath(); } }
toAbsolutePath
メソッドはユーザー入力を変換し、問合せを受けた場合に有益な値を返すPath
を返します。 このメソッドは、ファイルが存在していなくても動作します。
toRealPath
メソッドは、既存ファイルの実際のパスを返します。 このメソッドは、複数の処理を1回で実行します。
true
が渡され、ファイル・システムでシンボリック・リンクがサポートされている場合は、このメソッドにより、パス内のすべてのシンボリック・リンクが解決されます。
Path
が相対パスの場合は、絶対パスが返されます。
Path
に冗長な要素が含まれる場合は、冗長な要素を削除したパスが返されます。
ファイルが存在しない場合やアクセスできない場合は、このメソッドは例外をスローします。 これらの状況に対処するには、例外をキャッチします。 次のように処理します。
try { Path fp = path.toRealPath(true); } catch (NoSuchFileException x) { System.err.format("%s: no such file or directory%n", path); //ファイルが存在しない場合のロジック } catch (IOException x) { System.err.format("%s%n", x); //その他のファイル・エラーの場合のロジック }
resolve
メソッドを使用すると、パスを結合できます。 部分パス(ルート要素を含まないパス)を渡すと、その部分パスが元のパスに追加されます。
たとえば、次のコードについて考えてみましょう。
Path p1 = Paths.get("/home/joe/foo"); // Solaris System.out.format("%s%n", p1.resolve("bar")); // 結果は/home/joe/foo/bar または Path p1 = Paths.get("C:\\home\\joe\\foo"); // Microsoft Windows System.out.format("%s%n", p1.resolve("bar")); // 結果はC:\home\joe\foo\bar
resolve
メソッドの引数として絶対パスを渡すと、渡したパスが返されます。
Paths.get("foo").resolve("/home/joe"); // 結果は/home/joe
relativize
メソッドを使用して対応できます。 このメソッドにより、元のパスから、引数のパスが指定する場所までのパスが構成されます。 新しいパスは、元のパスに対する相対パスになります。
たとえば、joe
およびsally
として定義された2つの相対パスについて考えます。
Path p1 = Paths.get("joe"); Path p2 = Paths.get("sally");
joe
とsally
は兄弟ノード、すなわちツリー構造の同じレベルに位置するノードであると想定されます。 したがって、joe
からsally
に移動するには、まず1つ上位の親ノードに移動し、次にsally
に下がると考えることができます。
Path p1_to_p2 = p1.relativize(p2); // 結果は../sally Path p2_to_p1 = p2.relativize(p1); // 結果は../joe
Path p1 = Paths.get("home"); Path p3 = Paths.get("home/sally/bar"); Path p1_to_p3 = p1.relativize(p3); // 結果はsally/bar Path p3_to_p1 = p3.relativize(p1); // 結果は../..
home
を共有しています。 home
からbar
に移動するには、まず1つ下位のsally
に移動し、次にさらに1つ下位のbar
に移動します。 bar
からhome
に移動するには、2つ上位に移動する必要があります。
どちらか一方のパスのみにルート要素が含まれる場合は、相対パスは構成できません。 両方のパスにルート要素が含まれる場合は、相対パスを構成できるかどうかはシステムによって異なります。
再帰的なサンプル・プログラムのCopy
では、relativize
メソッドとresolve
メソッドを使用しています。
Path
クラスでは、equals
メソッドを使用して、2つのパスが等しいかどうかをチェックできます。 また、startsWith
メソッドを使用してパスが特定の文字列から始まるかをチェックし、endsWith
メソッドを使用して特定の文字列で終わるかをチェックできます。 これらのメソッドの使用法は簡単です。 次のように使用します。
Path path = ...; Path otherPath = ...; Path beginning = Paths.get("/home"); Path ending = Paths.get("foo"); if (path.equals(otherPath)) { //2つのパスが等しい場合のロジック } else if (path.startsWith(beginning)) { //パスが"/home"で始まる場合のロジック } else if (path.endsWith(ending)) { //パスが"foo"で終わる場合のロジック }
Path
クラスは、Iterable
インタフェースを実装しています。 iterator
メソッドにより、パス内の名前要素を反復処理できるオブジェクトが返されます。 返される最初の要素はディレクトリ・ツリー内のルートにもっとも近い要素です。 次のコードでは、パスを反復処理して、各名前要素を出力します。
Path path = ...; for (Path name: path) { System.out.println(name); }
Path
クラスは、Comparable
インタフェースも実装しています。 compareTo
を使用してPath
オブジェクトを比較できます。このメソッドはソート処理に便利です。
Path
オブジェクトをCollection
に格納することもできます。 この強力な機能に関する詳細は、Collectionsコースを参照してください。
2つのPath
オブジェクトが同じファイルを指しているかどうかをチェックする場合は、isSameFile
メソッドを使用できます。このメソッドについては、2つのパスの示すファイルが同一かどうかのチェックで説明しています。