チュートリアル

Java実践編:ファイル操作

Javaファイル操作実践
広告エリア

はじめに

Java実践編では、実際の開発で必要になるスキルを学びます。第1回はファイル操作です。

Java 7以降はjava.nio.fileパッケージの使用が推奨されています。

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

ファイルを読む

import java.nio.file.*;
import java.io.*;
import java.util.*;
import java.nio.charset.StandardCharsets;

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

        // ファイル全体を読み込む
        String content = Files.readString(path, StandardCharsets.UTF_8);
        System.out.println(content);

        // 全行をリストとして取得
        List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
        for (String line : lines) {
            System.out.println(line);
        }

        // 1行ずつストリームで処理(大容量ファイル向け)
        try (var stream = Files.lines(path, StandardCharsets.UTF_8)) {
            stream.forEach(System.out::println);
        }
    }
}

ファイルに書き込む

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class FileWriteExample {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("output.txt");

        // 新規作成・上書き
        Files.writeString(path, "こんにちは\nJava\n", StandardCharsets.UTF_8);

        // 追記
        Files.writeString(path, "追加の行\n",
            StandardCharsets.UTF_8,
            StandardOpenOption.APPEND);

        // 複数行を書き込み
        List<String> lines = List.of("1行目", "2行目", "3行目");
        Files.write(path, lines, StandardCharsets.UTF_8);

        // オプション指定
        Files.write(path, lines,
            StandardCharsets.UTF_8,
            StandardOpenOption.CREATE,
            StandardOpenOption.TRUNCATE_EXISTING);
    }
}

try-with-resourcesによるリソース管理

ファイルは自動的に閉じられます。

import java.io.*;
import java.nio.charset.StandardCharsets;

public class TryWithResourcesExample {
    public static void main(String[] args) {
        // 良い例(自動でclose)
        try (BufferedReader reader = new BufferedReader(
                new FileReader("file.txt", StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // ここでreaderは自動的に閉じられる

        // 複数リソースも可能
        try (
            var reader = new BufferedReader(new FileReader("input.txt"));
            var writer = new BufferedWriter(new FileWriter("output.txt"))
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

StandardOpenOption一覧

オプション説明
READ読み込みモード
WRITE書き込みモード
APPEND追記
CREATEファイルがなければ作成
CREATE_NEW新規作成(既存ならエラー)
TRUNCATE_EXISTING既存ファイルを空にする
DELETE_ON_CLOSEクローズ時に削除

BufferedReader/BufferedWriter

大容量ファイルの処理にはバッファリングが効果的です。

import java.io.*;
import java.nio.charset.StandardCharsets;

public class BufferedExample {
    public static void readLargeFile(String path) throws IOException {
        try (BufferedReader reader = Files.newBufferedReader(
                Path.of(path), StandardCharsets.UTF_8)) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 1行ずつ処理
                processLine(line);
            }
        }
    }

    public static void writeLargeFile(String path, List<String> data)
            throws IOException {
        try (BufferedWriter writer = Files.newBufferedWriter(
                Path.of(path), StandardCharsets.UTF_8)) {
            for (String line : data) {
                writer.write(line);
                writer.newLine();
            }
        }
    }
}

JSONファイルの操作

Jacksonライブラリを使用します。

<!-- pom.xml -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.util.*;

public class JsonExample {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        // JSONを読み込む
        User user = mapper.readValue(new File("user.json"), User.class);
        System.out.println(user.getName());

        // JSONに書き込む
        User newUser = new User("太郎", 25, List.of("Java", "Spring"));
        mapper.writerWithDefaultPrettyPrinter()
              .writeValue(new File("output.json"), newUser);

        // 文字列との変換
        String json = mapper.writeValueAsString(newUser);
        User parsed = mapper.readValue(json, User.class);
    }
}

class User {
    private String name;
    private int age;
    private List<String> skills;

    // コンストラクタ、getter、setter
    public User() {}

    public User(String name, int age, List<String> skills) {
        this.name = name;
        this.age = age;
        this.skills = skills;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public List<String> getSkills() { return skills; }
    public void setSkills(List<String> skills) { this.skills = skills; }
}

CSVファイルの操作

シンプルなCSV処理の例です。

import java.nio.file.*;
import java.util.*;
import java.nio.charset.StandardCharsets;

public class CsvExample {
    public static List<Map<String, String>> readCsv(String path)
            throws IOException {
        List<String> lines = Files.readAllLines(
            Path.of(path), StandardCharsets.UTF_8);

        if (lines.isEmpty()) return List.of();

        String[] headers = lines.get(0).split(",");
        List<Map<String, String>> result = new ArrayList<>();

        for (int i = 1; i < lines.size(); i++) {
            String[] values = lines.get(i).split(",");
            Map<String, String> row = new HashMap<>();
            for (int j = 0; j < headers.length; j++) {
                row.put(headers[j], j < values.length ? values[j] : "");
            }
            result.add(row);
        }

        return result;
    }

    public static void writeCsv(String path, List<Map<String, String>> data)
            throws IOException {
        if (data.isEmpty()) return;

        List<String> headers = new ArrayList<>(data.get(0).keySet());
        List<String> lines = new ArrayList<>();

        lines.add(String.join(",", headers));

        for (Map<String, String> row : data) {
            List<String> values = new ArrayList<>();
            for (String header : headers) {
                values.add(row.getOrDefault(header, ""));
            }
            lines.add(String.join(",", values));
        }

        Files.write(Path.of(path), lines, StandardCharsets.UTF_8);
    }
}

パス操作

import java.nio.file.*;

public class PathExample {
    public static void main(String[] args) {
        // パスの作成
        Path path = Path.of("documents", "report.txt");
        System.out.println(path);  // documents/report.txt

        // パス情報の取得
        Path filePath = Path.of("/home/user/documents/report.txt");
        System.out.println(filePath.getFileName());   // report.txt
        System.out.println(filePath.getParent());     // /home/user/documents
        System.out.println(filePath.getRoot());       // /
        System.out.println(filePath.getNameCount());  // 4

        // 絶対パスに変換
        Path absolute = Path.of("file.txt").toAbsolutePath();
        System.out.println(absolute);

        // パスの結合
        Path base = Path.of("/home/user");
        Path resolved = base.resolve("documents/file.txt");
        System.out.println(resolved);  // /home/user/documents/file.txt

        // パスの正規化
        Path normalized = Path.of("/foo/bar/../baz").normalize();
        System.out.println(normalized);  // /foo/baz
    }
}

ディレクトリ操作

import java.nio.file.*;
import java.io.IOException;

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

        // 存在確認
        System.out.println(Files.exists(path));
        System.out.println(Files.isRegularFile(path));
        System.out.println(Files.isDirectory(path));

        // ファイルサイズ
        System.out.println(Files.size(path));

        // ディレクトリ作成
        Files.createDirectory(Path.of("new_folder"));
        Files.createDirectories(Path.of("a/b/c"));

        // ディレクトリ内のファイル一覧
        try (var stream = Files.list(Path.of("."))) {
            stream.forEach(System.out::println);
        }

        // 再帰的にファイルを検索
        try (var stream = Files.walk(Path.of("."))) {
            stream.filter(p -> p.toString().endsWith(".java"))
                  .forEach(System.out::println);
        }

        // ファイル削除
        Files.delete(Path.of("file.txt"));
        Files.deleteIfExists(Path.of("maybe.txt"));

        // コピーと移動
        Files.copy(Path.of("src.txt"), Path.of("dst.txt"),
            StandardCopyOption.REPLACE_EXISTING);
        Files.move(Path.of("old.txt"), Path.of("new.txt"),
            StandardCopyOption.REPLACE_EXISTING);
    }
}

実践例:ログファイル処理

import java.nio.file.*;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.nio.charset.StandardCharsets;

public class LogProcessor {
    record ErrorEntry(int line, String content) {}

    public static List<ErrorEntry> parseLogFile(String logPath)
            throws IOException {
        List<ErrorEntry> errors = new ArrayList<>();
        int lineNum = 0;

        try (BufferedReader reader = Files.newBufferedReader(
                Path.of(logPath), StandardCharsets.UTF_8)) {
            String line;
            while ((line = reader.readLine()) != null) {
                lineNum++;
                if (line.contains("ERROR")) {
                    errors.add(new ErrorEntry(lineNum, line.trim()));
                }
            }
        }

        return errors;
    }

    public static void saveErrorReport(
            List<ErrorEntry> errors,
            String outputPath) throws IOException {

        try (BufferedWriter writer = Files.newBufferedWriter(
                Path.of(outputPath), StandardCharsets.UTF_8)) {

            String timestamp = LocalDateTime.now()
                .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

            writer.write("エラーレポート - " + timestamp);
            writer.newLine();
            writer.write("=".repeat(50));
            writer.newLine();
            writer.newLine();

            for (ErrorEntry error : errors) {
                writer.write("行 " + error.line() + ": " + error.content());
                writer.newLine();
            }

            writer.newLine();
            writer.write("合計: " + errors.size() + "件のエラー");
            writer.newLine();
        }
    }

    public static void main(String[] args) throws IOException {
        List<ErrorEntry> errors = parseLogFile("app.log");
        saveErrorReport(errors, "error_report.txt");
    }
}

まとめ

  • java.nio.file.Filesでモダンなファイル操作
  • try-with-resourcesで安全なリソース管理
  • StandardCharsets.UTF_8で文字エンコーディング指定
  • Jacksonライブラリ統合JSONを扱う
  • Pathでパス操作

次回は例外処理について学びます。

広告エリア