1. 概要

このチュートリアルでは、 NIO.2 API を使用してJavaでシンボリックリンクを作成するさまざまな方法を探り、ハードファイルリンクとソフトファイルリンクの違いを探ります。

2. ハードvsソフト/シンボリックリンク

まず、ファイルリンクとは何か、そしてそれらの予想される動作は何かを定義しましょう。 ファイルリンクは、ファイルシステムに保存されているファイルを透過的に参照するポインタです。

よくある誤解は、ファイルリンクがショートカットであると考えていることです。そのため、それらの動作を確認しましょう。

  • ショートカットは、ターゲットファイルを参照する通常のファイルです
  • ソフト/シンボリックリンクは、リンク先のファイルとして動作するファイルポインタです。ターゲットファイルが削除されると、リンクは使用できなくなります。
  • ハードリンクは、リンク先のファイルをミラーリングするファイルポインターであるため、基本的にはクローンのようなものです。 ターゲットファイルが削除されても、リンクファイルは引き続き有効です

ほとんどのオペレーティングシステム(Linux、Windows、Mac)はすでにソフト/ハードファイルリンクをサポートしているため、 NIOAPIを使用してそれらを処理することは問題ありません。

3. リンクの作成

まず、リンクするターゲットファイルを作成する必要があるので、いくつかのデータをファイルにシーケンスしてみましょう。

public Path createTextFile() throws IOException {		
    byte[] content = IntStream.range(0, 10000)
      .mapToObj(i -> i + System.lineSeparator())
      .reduce("", String::concat)
      .getBytes(StandardCharsets.UTF_8);
    Path filePath = Paths.get("", "target_link.txt");
    Files.write(filePath, content, CREATE, TRUNCATE_EXISTING);
    return filePath;		
}

作成したファイルがシンボリックリンクであることを確認して、既存のファイルへのシンボリックリンクを作成しましょう。

public void createSymbolicLink() throws IOException {
    Path target = createTextFile();
    Path link = Paths.get(".","symbolic_link.txt");
    if (Files.exists(link)) {
        Files.delete(link);
    }
    Files.createSymbolicLink(link, target);
}

次に、ハードリンクの作成を見てみましょう。

public void createHardLink() throws IOException {
    Path target = createTextFile();
    Path link = Paths.get(".", "hard_link.txt");
    if (Files.exists(link)) {
        Files.delete(link);
    }
    Files.createLink(link, target);
}

違いのあるファイルを一覧表示すると、ソフト/シンボリックリンクファイルのサイズが小さいのに対し、ハードリンクはリンクされたファイルと同じスペースを使用していることがわかります。

 48K	target_link.txt
 48K	hard_link.txt
4.0K	symbolic_link.txt

スローされる可能性のある例外を明確に理解するために、操作でチェックされた例外を見てみましょう。

  • UnsupportedOperationException –JVMが特定のシステムのファイルリンクをサポートしていない場合
  • FileAlreadyExistsException –リンクファイルがすでに存在する場合、オーバーライドはデフォルトではサポートされていません
  • IOException –IOエラーが発生した場合。 無効なファイルパス
  • SecurityException –ファイルのアクセス許可が制限されているためにリンクファイルを作成できない場合、またはターゲットファイルにアクセスできない場合

4. リンクを使用した操作

これで、既存のファイルリンクを持つ特定のファイルシステムがある場合、それらを識別してターゲットファイルを表示することができます。

public void printLinkFiles(Path path) throws IOException {
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
        for (Path file : stream) {
            if (Files.isDirectory(file)) {
                printLinkFiles(file);
            } else if (Files.isSymbolicLink(file)) {
                System.out.format("File link '%s' with target '%s' %n", 
                  file, Files.readSymbolicLink(file));
            }
        }
    }
}

現在のパスで実行すると、次のようになります。

printLinkFiles(Paths.get("."));

次の出力が得られます。

File link 'symbolic_link.txt' with target 'target_link.txt'

ハードリンクファイルはNIOのAPIで簡単に識別できるわけではないことに注意してください。この種のファイルを処理するには、低レベルの操作が必要です。

5. 結論

この記事では、さまざまなタイプのファイルリンク、ショートカットとの違い、および市場の主流のファイルシステムで機能する純粋なJavaAPIを使用してそれらを作成および操作する方法について説明します。

これらの例とコードスニペットの実装は、GitHubにあります。