プロジェクト

全般

プロフィール

Javaプログラミング ファイル操作

Java SE 7で導入されたNIO.2ライブラリ、Java SE 8で導入されたStream APIを含めた、Javaにおけるファイル操作のメモです。

ディレクトリ(パス)操作

カレントディレクトリを取得する

システムプロパティuser.dirを取得

システムプロパティuser.dirにはカレントディレクトリが格納されるので、これを取得します。

String cwd = System.getProperty("user.dir");

NIO.2でカレントディレクトリを示す.を指定して取得

Path cwd = Paths.get(".");
  • 注記)Paths.get(...)は、内部でFileSystems.getDefault().getPath(...)を呼ぶ

指定したパスのファイルオブジェクト(java.io.File)を生成する

相対パスで指定

File theFile = Paths.get("work", "input", "alfa.txt").toFile();

Pathsクラスのgetメソッドは、引数の数(1個か2個以上か)で振る舞いが変わるようです。詳細はJavadoc参照。

パスからファイル名を抜き出す

Path path = Paths.get(url.getPath());
String fileName = path.getFileName().toString();

指定したディレクトリ直下のディレクトリまたはファイルの一覧を取得

指定したディレクトリの直下(サブディレクトリがある場合、その中は対象外)にあるディレクトリとファイルの一覧を取得します。

NIO.2のDirectoryStreamを使用

try (DirectoryStream<Path> entries = Files.newDirectoryStream(Paths.get("."))) {
    entries.forEach(System.out::println);
} catch (IOException ex) {
    // ...
}

対象ディレクトリをPathで作成し、Files#newDirectoryStreamに渡します。対象ディレクトリの直下に存在するディレクトリとファイルの一覧が、Iterable<Path>型で返却されるので、イテレータ処理をします。ここでは、Iterableに加わったforEachを呼び出しています。

Stream APIを使用

try (Stream<Path> entries = Files.list(Paths.get("."))) {
    entries.forEach(System.out::println);
} catch (IOException ex) {
    // ...
}

対象ディレクトリをPathで作成し、Files#listに渡します。対象ディレクトリの直下に存在するディレクトリとファイルの一覧が、Stream<Path>型で返却されるので、Stream処理をします。ここでは、終端操作のforEachを呼び出しています。

指定したディレクトリ直下のディレクトリまたはファイルから特定の名前の一覧を取得

ディレクトリとファイル一覧から特定の名前のもの、例えば拡張子が.javaのもの、を抜粋します。

NIO.2のDirectoryStreamを使用

try (DirectoryStream<Path> entries = Files.newDirectoryStream(Paths.get("."), "*.java")) {
    entries.forEach(System.out::println);
} catch (IOException ex) {
    // ...
}

Files#newDirectoryStreamの第2引数で指定するのはglobパターンです。FileSystem#getPathMatcherメソッドのJavadocにglobパターンに使える記号の説明があります。このページのglobのパターンマッチングにも簡単に書き方を記述しています。

Stream APIを使用

try (Stream<Path> entries = Files.list(Paths.get("."))) {
    PathMatcher matcher = FileSytems.getDefault().getPathMatcher("glob:**.java");
    entries.filter(matcher::matches)
           .forEach(System.out::println);
} catch (IOException ex) {
    // ...
}

FileSystems#getDefault() で使用しているFileSystemインスタンスを取得し、それのgetPathMatcherで指定したパターンに合致するPathMatcherインスタンスを取得します。パターンには、globパターンと正規表現パターンの2種類が指定可能で、文字列の最初に指定する種類を記述します。

globのパターンマッチング

PathMacherでglob構文によるパターン指定をする際のルールをメモします。

記号 内容 備考
* 0文字以上の任意の文字、ただしディレクトリ区切り子をまたがない
** 0文字以上の任意の文字でディレクトリ区切り子をまたぐ
? 任意の1つの文字
{} パターンをカンマ区切りで複数記述し、いずれかにマッチ *.{cpp,h}
[] 1つの文字の集合 [aeiou] は、a,e,i,o,uのいずれか1文字と一致

指定したディレクトリの下を再帰的にディレクトリまたはファイルから特定の名前の一覧を取得

Stream APIを使用

指定したディレクトリ直下のディレクトリまたはファイル一覧を取得する際に使用したFilesクラスのメソッドlistを、walkメソッドに変更するだけです。

try (Stream<Path> entries = Files.walk(Paths.get("."))) {
    PathMatcher matcher = FileSytems.getDefault().getPathMatcher("glob:**.java");
    entries.filter(matcher::matches)
           .forEach(System.out::println);
} catch (IOException ex) {
    // ...
}

ファイルの読み込み

テキストファイルを読み込む

BufferedReaderを使って読み込む

ファイルの各行で、空白で区切った先頭の文字列を、重複なく(同じものは1回だけ)表示します。

try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName), Charset.forName("UTF-8"))) {
    reader.lines()
          .map(s -> s.split(" ")[0])
          .distinct()
          .forEach(System.out::println);
} catch (IOException ex) {
    // ファイルアクセスに関するエラー処理
}
  • Java SE 7で追加された try-with-resource構文を使って、tryスコープが終了するときにreaderがクローズされます。
  • Java SE 7で追加された NIO2パッケージのFilesクラスでファイルパスと文字コードを指定してBufferedReaderを生成します。
  • Java SE 8で追加された Stream APIを使って、読み込むファイルの各行について、空白で分割した最初の文字列を抜き出し(map)、重複する文字列は除外し(distinct)、残ったそれぞれの文字列について(forEach)コンソールに出力(System.out::println)します。
    lines()を読んだ時点ではファイルI/Oは発生しないので、大きなファイルを扱うことも問題なさそうです。一方、Files.readAllLinesを使うとヒープ領域に対して大きなファイルを扱う際にOutOfMemoryErrorが発生します。

クリップボードから画像を追加 (サイズの上限: 1 GB)