Java NIO2パスAPI
1概要
この記事では、Javaで新しいI/O(NIO2)
Path
APIを使用する方法を学びます。
NIO2の
Path
APIは、Java 7に同梱されている主要な新しい機能分野の1つであり、具体的にはFile 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
)に加えて、パス文字列部分(この場合は
articles
および
baeldung
)の可変引数パラメーターを受け取ることができます。
完全なパス文字列の代わりにこれらの部分を提供する場合、それらは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パスを結合する
2つのパスを結合するには、
resolve
メソッドを使用します。
簡単に言うと、任意の
Path
で
resolve
メソッドを呼び出し、
partial path
を引数として渡すことができます。その部分パスは、元のパスに追加されます。
@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
というディレクトリがあり、その中に他の2つのディレクトリがある場合、
/baeldung/authors
と
/baeldung/articles
が有効なパスになります。
authors
を基準にした
articles
へのパスは、
「ディレクトリ階層の1つ上のレベルに移動してからarticlesディレクトリに移動する」または
.. \ 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
フォルダに移動し、それらが兄弟ではなくなったとします。次の相対化操作では、
baeldung
と
articles
の間にパスを作成します。
@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)でPath操作を示し、それらのほとんどが実際に動作していることを確認しました。
この記事で使用したコードサンプルは、記事のhttps://github.com/eugenp/tutorials/tree/master/core-java-io[Githubプロジェクト]にあります。