1. 概要

この記事では、Javaで新しいI / O(NIO2) PathAPIを使用する方法を学習します。

NIO2のPath APIは、Java 7に付属する主要な新しい機能領域の1つであり、具体的には、ファイルAPIと並んで新しいファイルシステムAPIのサブセットです。

2. 設定

NIO2サポートは、java.nio.fileパッケージにバンドルされています。 したがって、 Path APIを使用するようにプロジェクトを設定するには、このパッケージのすべてをインポートするだけです。

import java.nio.file.*;

この記事のコードサンプルはおそらくさまざまな環境で実行されるため、ユーザーのホームディレクトリのハンドルを取得しましょう。

private static String HOME = System.getProperty("user.home");

この変数は、任意の環境で有効な場所を指します。

Paths クラスは、ファイルシステムパスに関連するすべての操作への主要なエントリポイントです。 これにより、ファイルやディレクトリへのパスを作成および操作できます。

注目に値するのは、パス操作は主に構文的な性質のものであるということです。 それらは基礎となるファイルシステムに影響を与えず、ファイルシステムもそれらが成功するか失敗するかに影響を与えません。 これは、パス操作のパラメーターとして存在しないパスを渡すことは、それが成功するか失敗するかに関係がないことを意味します。

3. パス操作

このセクションでは、パス操作で使用される主な構文を紹介します。 その名前が示すように、 Path クラスは、ファイルシステム内のパスをプログラムで表現したものです。

Path オブジェクトには、パスの作成に使用されるファイル名とディレクトリリストが含まれ、ファイルの調査、検索、および操作に使用されます。

ヘルパークラスjava.nio.file.Paths(複数形)は、Pathオブジェクトを作成する正式な方法です。 パス文字列からPathを作成するための2つの静的メソッドがあります。

Path path = Paths.get("path string");

パスString、でスラッシュを使用するかバックスラッシュを使用するかは関係ありませんが、APIは、基になるファイルシステムの要件に従ってこのパラメーターを解決します。

そして、 java.net.URI オブジェクトから:

Path path = Paths.get(URI object);

これで、これらの動作を確認できます。

4. パスの作成

パス文字列からPathオブジェクトを作成するには:

@Test
public void givenPathString_whenCreatesPathObject_thenCorrect() {
    Path p = Paths.get("/articles/baeldung");
 
    assertEquals("\\articles\\baeldung", p.toString());
}

get APIは、最初の部分(この場合)に加えて、パス文字列部分(この場合はarticlesおよびbaeldung)の可変引数パラメーターを受け取ることができます。 、 articles )。

完全なパス文字列の代わりにこれらの部分を提供する場合、Pathオブジェクトを構築するために使用されます。可変引数部分に名前区切り文字(スラッシュ)を含める必要はありません。

@Test
public void givenPathParts_whenCreatesPathObject_thenCorrect() {
    Path p = Paths.get("/articles", "baeldung");
    
    assertEquals("\\articles\\baeldung", p.toString());
}

5. パス情報の取得

Pathオブジェクトは、シーケンスとしての名前要素と考えることができます。 E:\ baeldung \ articles \javaなどのパスStringは、3つの名前要素で構成されます。 baeldung articles 、およびjava。 ディレクトリ構造の最上位の要素はインデックス0にあり、この場合はbaeldungです。

ディレクトリ構造の最下位の要素は、インデックス [n-1] にあります。ここで、nはパス内の名前要素の数です。 この最も低い要素は、実際のファイルであるかどうかに関係なく、ファイル名と呼ばれます。

@Test
public void givenPath_whenRetrievesFileName_thenCorrect() {
    Path p = Paths.get("/articles/baeldung/logs");

    Path fileName = p.getFileName();
 
    assertEquals("logs", fileName.toString());
}

インデックスによって個々の要素を取得するためのメソッドを使用できます。

@Test
public void givenPath_whenRetrievesNameByIndex_thenCorrect() {
    Path p = Paths.get("/articles/baeldung/logs");
    Path name0 = getName(0);
    Path name1 = getName(1);
    Path name2 = getName(2);
    assertEquals("articles", name0.toString());
    assertEquals("baeldung", name1.toString());
    assertEquals("logs", name2.toString());
}

または、次のインデックス範囲を使用したパスのサブシーケンス:

@Test
public void givenPath_whenCanRetrieveSubsequenceByIndex_thenCorrect() {
    Path p = Paths.get("/articles/baeldung/logs");

    Path subPath1 = p.subpath(0,1);
    Path subPath2 = p.subpath(0,2);
 
    assertEquals("articles", subPath1.toString());
    assertEquals("articles\\baeldung", subPath2.toString());
    assertEquals("articles\\baeldung\\logs", p.subpath(0, 3).toString());
    assertEquals("baeldung", p.subpath(1, 2).toString());
    assertEquals("baeldung\\logs", p.subpath(1, 3).toString());
    assertEquals("logs", p.subpath(2, 3).toString());
}

各パスは親パスに関連付けられており、パスに親がない場合はnullに関連付けられています。 パスオブジェクトの親は、パスのルートコンポーネント(存在する場合)と、ファイル名を除くパス内の各要素で構成されます。 例として、 / a / b /cの親パスは/a / b であり、 /aの親パスはnullです。

@Test
public void givenPath_whenRetrievesParent_thenCorrect() {
    Path p1 = Paths.get("/articles/baeldung/logs");
    Path p2 = Paths.get("/articles/baeldung");
    Path p3 = Paths.get("/articles");
    Path p4 = Paths.get("/");

    Path parent1 = p1.getParent();
    Path parent2 = p2.getParent();
    Path parent3 = p3.getParent();
    Path parent4 = p4.getParenth();

    assertEquals("\\articles\\baeldung", parent1.toString());
    assertEquals("\\articles", parent2.toString());
    assertEquals("\\", parent3.toString());
    assertEquals(null, parent4);
}

パスのルート要素を取得することもできます。

@Test
public void givenPath_whenRetrievesRoot_thenCorrect() {
    Path p1 = Paths.get("/articles/baeldung/logs");
    Path p2 = Paths.get("c:/articles/baeldung/logs");

    Path root1 = p1.getRoot();
    Path root2 = p2.getRoot();

    assertEquals("\\", root1.toString());
    assertEquals("c:\\", root2.toString());
}

6. パスの正規化

多くのファイルシステムでは、“。” 表記を使用して現在のディレクトリを示し、“ ..”を使用して親ディレクトリを示します。 パスに冗長なディレクトリ情報が含まれている場合があります。

たとえば、次のパス文字列について考えてみます。

/baeldung/./articles
/baeldung/authors/../articles
/baeldung/articles

それらはすべて同じ場所/baeldung /articlesに解決されます。 最初の2つには冗長性がありますが、最後の2つには冗長性がありません。

パスを正規化するには、パス内の冗長性を削除する必要があります。 Path.normalize()操作は、この目的のために提供されています。

この例は、一目瞭然です。

@Test
public void givenPath_whenRemovesRedundancies_thenCorrect1() {
    Path p = Paths.get("/home/./baeldung/articles");

    Path cleanPath = p.normalize();
 
    assertEquals("\\home\\baeldung\\articles", cleanPath.toString());
}

これも:

@Test
public void givenPath_whenRemovesRedundancies_thenCorrect2() {
    Path p = Paths.get("/home/baeldung/../articles");

    Path cleanPath = p.normalize();
 
    assertEquals("\\home\\articles", cleanPath.toString());
}

7. パス変換

パスを選択したプレゼンテーション形式に変換する操作があります。 パスをブラウザから開くことができる文字列に変換するには、toUriメソッドを使用します。

@Test
public void givenPath_whenConvertsToBrowseablePath_thenCorrect() {
    Path p = Paths.get("/home/baeldung/articles.html");

    URI uri = p.toUri();
    assertEquals(
      "file:///E:/home/baeldung/articles.html", 
        uri.toString());
}

パスをその絶対表現に変換することもできます。 toAbsolutePath メソッドは、ファイルシステムのデフォルトディレクトリに対するパスを解決します。

@Test
public void givenPath_whenConvertsToAbsolutePath_thenCorrect() {
    Path p = Paths.get("/home/baeldung/articles.html");

    Path absPath = p.toAbsolutePath();
 
    assertEquals(
      "E:\\home\\baeldung\\articles.html", 
        absPath.toString());
}

ただし、解決されるパスがすでに絶対であることが検出された場合、メソッドはそれをそのまま返します。

@Test
public void givenAbsolutePath_whenRetainsAsAbsolute_thenCorrect() {
    Path p = Paths.get("E:\\home\\baeldung\\articles.html");

    Path absPath = p.toAbsolutePath();
 
    assertEquals(
      "E:\\home\\baeldung\\articles.html", 
        absPath.toString());
}

toRealPath メソッドを呼び出すことにより、任意のパスを実際の同等のパスに変換することもできます。 このメソッドは、パスの要素をファイルシステム内の実際のディレクトリおよびファイルにマッピングすることにより、パスを解決しようとします。

Setup セクションで作成した、ファイルシステム内のログインユーザーのホームロケーションを指す変数を使用する時間:

@Test
public void givenExistingPath_whenGetsRealPathToFile_thenCorrect() {
    Path p = Paths.get(HOME);

    Path realPath = p.toRealPath();
 
    assertEquals(HOME, realPath.toString());
}

上記のテストでは、この操作の動作についてはあまりわかりません。 最も明白な結果は、パスがファイルシステムに存在しない場合、操作は IOException をスローし、読み進めます。

このポイントを家に帰すためのより良い方法がないため、存在しないパスを実際のパスに変換しようとする次のテストを見てください。

@Test(expected = NoSuchFileException.class)
public void givenInExistentPath_whenFailsToConvert_thenCorrect() {
    Path p = Paths.get("E:\\home\\baeldung\\articles.html");
    
    p.toRealPath();
}

IOException をキャッチすると、テストは成功します。 この操作がスローするIOExceptionの実際のサブクラスは、NoSuchFileExceptionです。

8. パスの結合

resolve メソッドを使用して、任意の2つのパスを結合できます。

簡単に言うと、任意のPathresolveメソッドを呼び出し、部分パスを引数として渡すことができます。 その部分的なパスが元のパスに追加されます。

@Test
public void givenTwoPaths_whenJoinsAndResolves_thenCorrect() {
    Path p = Paths.get("/baeldung/articles");

    Path p2 = p.resolve("java");
 
    assertEquals("\\baeldung\\articles\\java", p2.toString());
}

ただし、resolveメソッドに渡されるパス文字列が部分パスではない場合。 特に絶対パスの場合、渡されたパスが返されます。

@Test
public void givenAbsolutePath_whenResolutionRetainsIt_thenCorrect() {
    Path p = Paths.get("/baeldung/articles");

    Path p2 = p.resolve("C:\\baeldung\\articles\java");
 
    assertEquals("C:\\baeldung\\articles\\java", p2.toString());
}

ルート要素を持つパスでも同じことが起こります。 パス文字列“ java” にはルート要素がありませんが、パス文字列“ / java”にはルート要素があります。 したがって、ルート要素を含むパスを渡すと、次のように返されます。

@Test
public void givenPathWithRoot_whenResolutionRetainsIt_thenCorrect2() {
    Path p = Paths.get("/baeldung/articles");

    Path p2 = p.resolve("/java");
 
    assertEquals("\\java", p2.toString());
}

9.相対化パス

相対化という用語は、単に2つの既知のパスの間に直接パスを作成することを意味します。 たとえば、ディレクトリ / baeldung があり、その中に / baeldung /authors/baeldung /articlesが有効であるような2つのディレクトリがあります。パス。

authorsに対するarticlesへのパスは、「ディレクトリ階層の1つ上のレベルに移動してから、articlesディレクトリに移動する」または..\として記述されます。記事:

@Test
public void givenSiblingPaths_whenCreatesPathToOther_thenCorrect() {
    Path p1 = Paths.get("articles");
    Path p2 = Paths.get("authors");

    Path p1_rel_p2 = p1.relativize(p2);
    Path p2_rel_p1 = p2.relativize(p1);
 
    assertEquals("..\\authors", p1_rel_p2.toString());
    assertEquals("..\\articles", p2_rel_p1.toString());
}

articlesディレクトリをauthorsフォルダに移動して、兄弟ではなくなったと仮定します。 次の相対化操作には、baeldungarticlesの間、およびその逆のパスの作成が含まれます。

@Test
public void givenNonSiblingPaths_whenCreatesPathToOther_thenCorrect() {
    Path p1 = Paths.get("/baeldung");
    Path p2 = Paths.get("/baeldung/authors/articles");

    Path p1_rel_p2 = p1.relativize(p2);
    Path p2_rel_p1 = p2.relativize(p1);
 
    assertEquals("authors\\articles", p1_rel_p2.toString());
    assertEquals("..\\..", p2_rel_p1.toString());
}

10. パスの比較

Path クラスには、 equals メソッドの直感的な実装があり、2つのパスが等しいかどうかを比較できます。

@Test
public void givenTwoPaths_whenTestsEquality_thenCorrect() {
    Path p1 = Paths.get("/baeldung/articles");
    Path p2 = Paths.get("/baeldung/articles");
    Path p3 = Paths.get("/baeldung/authors");

    assertTrue(p1.equals(p2));
    assertFalse(p1.equals(p3));
}

パスが特定の文字列で始まるかどうかを確認することもできます。

@Test
public void givenPath_whenInspectsStart_thenCorrect() {
    Path p1 = Paths.get("/baeldung/articles");
 
    assertTrue(p1.startsWith("/baeldung"));
}

または、他の文字列で終了します。

@Test
public void givenPath_whenInspectsEnd_thenCorrect() {
    Path p1 = Paths.get("/baeldung/articles");
  
    assertTrue(p1.endsWith("articles"));
}

11. 結論

この記事では、Java 7の一部として出荷された新しいファイルシステムAPI(NIO2)でのパス操作を示し、それらのほとんどが実際に動作していることを確認しました。

この記事で使用されているコードサンプルは、記事のGithubプロジェクトにあります。