Java | Java 標準ライブラリ:Path / Paths

Java Java
スポンサーリンク

Path / Paths をざっくり一言でいうと

Path は、

「ファイルやディレクトリまでの“道順(パス)”を表すオブジェクト」です。

Paths は、

Path を作るための “工場(ファクトリ)クラス”」

です。

昔の File と違って、Path

  • OS に依存しない形でパスを扱える
  • パス同士の結合・分解・正規化(../ を消すなど)がやりやすい
  • Files クラスと組み合わせて、読み書き・コピー・削除など何でもできる

といった modern な API になっています。


Path の基本イメージと作り方

Path は「場所だけ」を表す(中身は読まない)

まず一番大事なのは、Path 自体は
「場所(パス)」を表すだけで、ファイルの中身は扱わないということです。

import java.nio.file.Path;

public class PathBasic {
    public static void main(String[] args) {
        Path p = Path.of("data/example.txt"); // Java 11 以降

        System.out.println(p);                // data/example.txt
    }
}
Java

この時点では、
data/example.txt というパスを指しています」と宣言しただけで、
ファイルが存在するかどうか、開いているかどうかは一切関係ありません。

実際の読み書きは、あとで Files やストリームと組み合わせて行います。

Path の作り方(Path.of と Paths.get)

よく使う作り方は 2 パターンです。

import java.nio.file.Path;
import java.nio.file.Paths;

public class CreatePath {
    public static void main(String[] args) {
        // Java 11 以降推奨
        Path p1 = Path.of("logs/app.log");

        // 古くからある方法(Java 7+)
        Path p2 = Paths.get("logs", "app.log");   // パス要素を分けて渡す

        System.out.println(p1);
        System.out.println(p2);
    }
}
Java

Paths.get は「可変長引数」なので、

  • Paths.get("logs/app.log")
  • Paths.get("logs", "2025", "01", "app.log")

のように、「フォルダごとに区切って渡す」こともできます。
OS によって区切り文字(/\)が違っても、Paths.get がうまく吸収してくれます。


絶対パス・相対パス・正規化(../ をきれいにする)

絶対パスと相対パス

Path は、相対パスでも絶対パスでも表せます。

Path relative = Path.of("logs/app.log");  // カレントディレクトリからの相対パス
Path absolute = relative.toAbsolutePath(); // 絶対パスに変換

System.out.println("相対: " + relative);
System.out.println("絶対: " + absolute);
Java

toAbsolutePath() を使うと、
「実際にはどの場所を指しているのか」がはっきり見えるので、
デバッグ時にかなり役立ちます。

.. や . をきれいに消す normalize

パスの中に ... が含まれていても、
normalize() でスッキリさせられます。

Path p = Path.of("logs/../logs/./2025/app.log");
System.out.println("そのまま: " + p);            // logs/../logs/./2025/app.log

Path normalized = p.normalize();
System.out.println("正規化後: " + normalized);  // logs/2025/app.log
Java

normalize() は、

  • .(カレント)を消す
  • x/.. のような、「一度下って戻る」部分をいい感じに畳む

ことで、「最短のパス表現」にしてくれます。


Path 同士の結合・相対パス計算(resolve / relativize)

resolve でパスをつなげる

resolve は、
「親パスに子のパス要素をつなげる」メソッドです。

import java.nio.file.Path;

public class ResolveExample {
    public static void main(String[] args) {
        Path base = Path.of("logs");
        Path child = Path.of("2025/app.log");

        Path combined = base.resolve(child);

        System.out.println(combined); // logs/2025/app.log
    }
}
Java

文字列の足し算("logs/" + "2025/app.log")でやるよりも安全で、
OS による区切り文字の違いも気にしなくてよくなります。

relativize で「ベースからの相対パス」を求める

relativize は、
「あるパスから見て、別のパスまでの相対パス」を計算します。

import java.nio.file.Path;

public class RelativizeExample {
    public static void main(String[] args) {
        Path base   = Path.of("logs");
        Path target = Path.of("logs/2025/01/app.log");

        Path relative = base.relativize(target);
        System.out.println(relative); // 2025/01/app.log

        Path back = target.relativize(base);
        System.out.println(back);     // ../..
    }
}
Java
  • logs から logs/2025/01/app.log を見ると 2025/01/app.log
  • 逆方向だと ../..

というように、相対移動のパスが手に入ります。


Path と Files の組み合わせでファイル操作を行う

Files.exists / isRegularFile / isDirectory

Path は「住所」なので、
実際の存在チェックや属性チェックは Files クラスで行います。

import java.nio.file.*;

public class FilesCheck {
    public static void main(String[] args) throws Exception {
        Path p = Path.of("data.txt");

        System.out.println("存在する?       : " + Files.exists(p));
        System.out.println("通常のファイル? : " + Files.isRegularFile(p));
        System.out.println("ディレクトリ?   : " + Files.isDirectory(p));
    }
}
Java

java.io.Fileexists()/isFile()/isDirectory() と似ていますが、
Files + Path の方が新しく、より強力です。

1 行で読み書き:readString / writeString

Path があれば、ファイルの読み書きはかなりシンプルに書けます。

import java.nio.file.*;

public class FilesReadWrite {
    public static void main(String[] args) throws Exception {
        Path path = Path.of("sample.txt");

        // 書き込み(上書き)
        Files.writeString(path, "Hello\nWorld\n");

        // 読み込み
        String content = Files.readString(path);
        System.out.println(content);
    }
}
Java

テキストファイルを扱う「最短ルート」はほぼこれです。
Path は単なる場所、実際の I/O は Files が担当する、という役割分担になっています。


File と Path の違い・相互変換(ここをしっかり理解する)

なぜ今は Path を使うべきと言われるのか

古い java.io.File と比べて、Path / Files にはこんな利点があります。

  • 例外ベースでエラーが分かりやすい(File は true/false だけで曖昧になりがち)
  • パス操作(結合・正規化・相対化)が高機能で直感的
  • シンボリックリンク・属性情報など、より多くの情報にアクセスしやすい
  • ファイル監視や大規模ファイル操作にも向いた modern API

なので、新しく書くコードでは基本 Path / Files を使うのが推奨されています。

File ↔ Path の相互変換

とはいえ、既存ライブラリは File を受け取ることが多いので、
相互変換のやり方も覚えておきましょう。

import java.io.File;
import java.nio.file.Path;

public class FilePathConvert {
    public static void main(String[] args) {
        // File → Path
        File file = new File("data.txt");
        Path pathFromFile = file.toPath();

        // Path → File
        Path path = Path.of("data.txt");
        File fileFromPath = path.toFile();

        System.out.println(pathFromFile);
        System.out.println(fileFromPath.getAbsolutePath());
    }
}
Java

File#toPath()Path#toFile() がセットになっています。


まとめ:Path / Paths を自分の中でこう位置づける

Path / Paths を初心者向けに整理すると、こうなります。

  • Path は、ファイルやディレクトリまでの「道順」を表すインターフェース
  • Paths(と Path.of)は、その Path を作るための“工場”
  • Path 自体は中身を読まない。存在チェックや読み書きは Files と組み合わせて行う
  • パスの結合(resolve)、相対パス計算(relativize)、正規化(normalize)が強力
  • File より新しく、modern なファイル操作の標準 API なので、新規コードでは基本こっち

タイトルとURLをコピーしました