LoginSignup
7
7

Javaでよくやるファイル操作(NIO.2編)

Last updated at Posted at 2023-05-17

環境

JDK 17

主要なクラス・インタフェース

ファイル操作に関するクラス・インタフェースの多くはjava.nio.fileパッケージに属しています。

これらのクラス・インタフェースを総称して「NIO.2」と呼ばれます。

Pathインタフェース

Pathインタフェースは、名前の通りファイルやディレクトリのパスを表します。Path.of("ファイルやディレクトリのパス")Pathオブジェクトを生成できます。

Path targetFile = Path.of("/tmp/test/sample.txt");

Filesクラス

ファイルまたはディレクトリに関する操作(読み込みや書き込みなど)はFilesクラスのstaticメソッドとしてまとまっています。

いろんなメソッドが用意されているので、ぜひJavadocを一通り眺めてみてください!

文字コード

文字コードはCharset抽象クラスが表します。Charset.forName("文字コード名")で、指定した文字コードを表すCharsetオブジェクトを生成できます。

MS932(Windowsデフォルトの文字コード)を取得する例
Charset cs = Charset.forName("MS932");
EUC-JPを取得する例
Charset cs = Charset.forName("EUC-JP");

文字コード名が正しくない場合はUnsupportedCharsetExceptionがスローされます。

UTF-8やUTF-16などを指定する場合はStandardCharsetsクラスの定数を利用できます。

Charset cs = StandardCharsets.UTF_8;
Charset cs = StandardCharsets.UTF_16;

テキストファイルの読み込み

/tmp/test/sample.txt(読み込み対象)
あいうえお
かきくけこ
さしすせそ

1行ずつ読み込んで加工する

Files.lines()メソッドを利用すると、各行を要素に持つStream<String>を取得できます。

今回は各行を[]で囲うように変換します。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        // 処理終了後に自動的にStreamがclose()されるようにtry-with-resourcesを利用
        try (Stream<String> stream = Files.lines(targetFile, StandardCharsets.UTF_8)) {
            // 各行を[]で囲う
            List<String> list = stream.map(line -> "[" + line + "]")
                    .toList();
            for (String line : list) {
                // 読み込んだ行に対して何らかの処理を行う
                // 今回はサンプルなので表示するだけ
                System.out.println(line);
            }
        } catch (IOException e) {
            // 業務コードでe.printStackTrace()を使うことはめったにありません。
            // 業務では各プロジェクトのルールに合わせて、例外の再スローやログの出力などを行ってください。
            e.printStackTrace();
        }
    }
}

引数がPathのみで文字コードを指定しないlines()メソッドもあります。このメソッドでは、文字コードはUTF-8になります。

実行結果
[あいうえお]
[かきくけこ]
[さしすせそ]

BufferedReaderを使う

ほとんどの場合はFiles.lines()メソッドで事足りると思います。

しかし、どうしても従来のBufferedReaderを使いたい場合は、Files.newBufferedReader()メソッドで取得できます。

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        // 処理終了後に自動的にBufferedReaderがclose()されるようにtry-with-resourcesを利用
        try (BufferedReader reader = Files.newBufferedReader(
                targetFile, StandardCharsets.UTF_8)) {
            // reader.readLine()で次の1行を読み込む(ファイルの末尾に到達した場合はnullを返す)
            for (String line; (line = reader.readLine()) != null;) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行結果
あいうえお
かきくけこ
さしすせそ

全行を保持するListを生成する

Files.readAllLines()を利用します。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try {
            // 1要素=1行であるListを生成する
            List<String> lines = Files.readAllLines(targetFile, StandardCharsets.UTF_8);
            for (String line : lines) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行結果
あいうえお
かきくけこ
さしすせそ

このメソッドはファイルの全内容を一気に読み込むので、ファイルが非常に大きい場合にOutOfMemoryErrorを引き起こす可能性があります。テキストファイルのサイズが実行環境のメモリ量より十分に小さい場合のみ、このメソッドを利用してください。

ファイルの全内容を1つの文字列として取得する

Files.readString()を利用します。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try {
            String content = Files.readString(targetFile, StandardCharsets.UTF_8);
            System.out.println(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行結果
あいうえお
かきくけこ
さしすせそ

このメソッドも、ファイルの全内容を一気に読み込むので注意してください。

テキストファイルの書き込み

/tmp/test/sample.txt(書き込み対象)
あいうえお
かきくけこ
さしすせそ

StandardOpenOption

StandardOpenOption列挙型は、ファイルの開き方および作成方法を表します。

後述するFilesクラスの各メソッドでは、最後の引数にStandardOpenOptionを指定します(可変長引数なので複数指定可能)。

  • CREATE
    • ファイルが存在しない場合は新規作成します。
    • ファイルが存在する場合は何もしません。
  • CREATE_NEW
    • ファイルが存在しない場合は新規作成します。
    • ファイルが存在する場合は例外がスローされます。
  • APPEND
    • 既存の内容の最後に追記します。
  • TRUNCATE_EXISTING
    • 既存の内容を上書きします。

1行だけ書き込む(追記)

Files.writeString()を利用します。

第4引数(可変長)にStandardOpenOption.CREATE(ファイルが存在する場合に例外にするならStandardOpenOption.CREATE_NEW)・StandardOpenOption.APPENDを指定すると、ファイル末尾への追記ができます。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try {
            Files.writeString(targetFile, "たちつてと", StandardCharsets.UTF_8,
                StandardOpenOption.CREATE,
                StandardOpenOption.APPEND);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行後の/tmp/test/sample.txt
あいうえお
かきくけこ
さしすせそ
たちつてと

1行だけ書き込む(上書き)

Files.writeString()メソッドを利用します。

第4引数(可変長)にStandardOpenOption.CREATE(ファイルが存在する場合に例外にするならStandardOpenOption.CREATE_NEW)・StandardOpenOption.TRUNCATE_EXISTINGを指定すると、上書きになります。つまり、以前のファイルの内容は削除されます。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try {
            Files.writeString(targetFile, "たちつてと", StandardCharsets.UTF_8,
                StandardOpenOption.CREATE,
                StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行後の/tmp/test/sample.txt
たちつてと

複数行を一気に書き込む(追記)

Files.write()を利用します。

第4引数(可変長)にStandardOpenOption.CREATE(ファイルが存在する場合に例外にするならStandardOpenOption.CREATE_NEW)・StandardOpenOption.APPENDを指定すると、ファイル末尾への追記ができます。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try {
            List<String> lines = List.of("たちつてと", "なにぬねの", "はひふへほ");
            Files.write(targetFile, lines, StandardCharsets.UTF_8,
                StandardOpenOption.CREATE,
                StandardOpenOption.APPEND);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行後の/tmp/test/sample.txt
あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
はひふへほ

複数行を一気に書き込む(上書き)

第4引数(可変長)にStandardOpenOption.CREATE(ファイルが存在する場合に例外にするならStandardOpenOption.CREATE_NEW)・StandardOpenOption.TRUNCATE_EXISTINGを指定すると、上書きになります。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try {
            List<String> lines = List.of("たちつてと", "なにぬねの", "はひふへほ");
            Files.write(targetFile, lines, StandardCharsets.UTF_8,
                StandardOpenOption.CREATE,
                StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行後の/tmp/test/sample.txt
たちつてと
なにぬねの
はひふへほ

書き込み時の改行コードを明示的に指定

writeString()write()では、改行コードは実行したOSのデフォルト(macOSとLinuxはLF、WindowsはCRLF)となります。

デフォルトでない改行コードを指定したい場合は、BufferedWriterクラスのwrite()メソッドを利用します。

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Path targetFile = Path.of("/tmp/test/sample.txt");
        try (BufferedWriter bufferedWriter = Files.newBufferedWriter(targetFile,
                StandardCharsets.UTF_8,
                StandardOpenOption.CREATE,
                StandardOpenOption.TRUNCATE_EXISTING)) {
            List<String> lines = List.of("たちつてと", "なにぬねの", "はひふへほ");
            for (String line : lines) {
                bufferedWriter.write(line);
                bufferedWriter.write("\r\n");  // 改行コードにCRLFを指定(LFの場合は"\n")
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
実行後の/tmp/test/sample.txt
たちつてと
なにぬねの
はひふへほ

StandardOpenOptionCREATE_NEWAPPENDでもOKです。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7