Rustのファイル読み書き入門:fs・BufReader・BufWriterの使い方

スポンサーリンク

Rustのファイル読み書き入門:fs・BufReader・BufWriterの使い方

はじめに

Rustでファイルを読み書きするには std::fs モジュールを使います。シンプルな一括読み込みから、大きなファイルを効率的に処理するバッファリングまでまとめます。


ファイルを読む

全体を文字列として読む(最もシンプル)

use std::fs;

fn main() {
    let content = fs::read_to_string("hello.txt").unwrap();
    println!("{}", content);
}

小〜中サイズのファイルならこれで十分です。エラー処理を加える場合:

use std::fs;

fn main() {
    match fs::read_to_string("hello.txt") {
        Ok(content) => println!("{}", content),
        Err(e) => eprintln!("エラー: {}", e),
    }
}

バイト列として読む

use std::fs;

fn main() {
    let bytes = fs::read("image.png").unwrap();
    println!("ファイルサイズ: {} バイト", bytes.len());
}

1行ずつ読む(大きなファイル向け)

BufReader を使うとファイル全体をメモリに載せずに1行ずつ処理できます。

use std::fs::File;
use std::io::{self, BufRead};

fn main() {
    let file = File::open("hello.txt").unwrap();
    let reader = io::BufReader::new(file);

    for line in reader.lines() {
        let line = line.unwrap();
        println!("{}", line);
    }
}

ファイルに書く

全体をまとめて書く(上書き)

use std::fs;

fn main() {
    fs::write("output.txt", "Hello, Rust!\n").unwrap();
}

バイト列を書く場合:

use std::fs;

fn main() {
    let data: Vec<u8> = vec![72, 101, 108, 108, 111];
    fs::write("output.bin", &data).unwrap();
}

追記する

use std::fs::OpenOptions;
use std::io::Write;

fn main() {
    let mut file = OpenOptions::new()
        .append(true)
        .create(true)        // ファイルがなければ作成
        .open("log.txt")
        .unwrap();

    writeln!(file, "ログメッセージ").unwrap();
}

BufWriter でまとめて書く(効率的)

大量の書き込みには BufWriter を使うとシステムコールをまとめて減らせます。

use std::fs::File;
use std::io::{self, BufWriter, Write};

fn main() {
    let file = File::create("output.txt").unwrap();
    let mut writer = BufWriter::new(file);

    for i in 0..1000 {
        writeln!(writer, "行 {}", i).unwrap();
    }
    // writer がドロップされるときに自動でフラッシュされる
}

OpenOptions で細かく制御する

use std::fs::OpenOptions;

let file = OpenOptions::new()
    .read(true)       // 読み込み許可
    .write(true)      // 書き込み許可
    .create(true)     // なければ作成
    .truncate(true)   // 既存内容を消去(上書き)
    .append(false)
    .open("file.txt")
    .unwrap();
オプション 説明
.read(true) 読み込み可能にする
.write(true) 書き込み可能にする
.create(true) ファイルがなければ作成
.create_new(true) ファイルが既にあればエラー
.truncate(true) 既存の内容を消して上書き
.append(true) 末尾に追記する

ファイル・ディレクトリ操作

ファイルのコピー・削除・リネーム

use std::fs;

// コピー
fs::copy("src.txt", "dst.txt").unwrap();

// 削除
fs::remove_file("old.txt").unwrap();

// リネーム(移動も兼ねる)
fs::rename("old.txt", "new.txt").unwrap();

ディレクトリ操作

use std::fs;

// ディレクトリを作成
fs::create_dir("my_dir").unwrap();

// ネストしたディレクトリを一括作成
fs::create_dir_all("a/b/c").unwrap();

// ディレクトリを削除(空のみ)
fs::remove_dir("my_dir").unwrap();

// ディレクトリを中身ごと削除
fs::remove_dir_all("my_dir").unwrap();

ディレクトリの一覧を取得

use std::fs;

for entry in fs::read_dir(".").unwrap() {
    let entry = entry.unwrap();
    println!("{}", entry.file_name().to_string_lossy());
}

ファイルのメタデータ

use std::fs;

let meta = fs::metadata("hello.txt").unwrap();

println!("サイズ: {} バイト", meta.len());
println!("ファイルか: {}", meta.is_file());
println!("ディレクトリか: {}", meta.is_dir());

エラーハンドリングと ? 演算子

実際のコードでは unwrap() の代わりに ? 演算子を使うのが一般的です。

use std::fs;
use std::io;

fn read_file(path: &str) -> Result<String, io::Error> {
    let content = fs::read_to_string(path)?;
    Ok(content)
}

fn main() {
    match read_file("hello.txt") {
        Ok(content) => println!("{}", content),
        Err(e) => eprintln!("読み込みエラー: {}", e),
    }
}

まとめ

やりたいこと 方法
ファイルを文字列で読む fs::read_to_string(path)
バイト列で読む fs::read(path)
1行ずつ読む BufReader::new(file).lines()
ファイルに書く(上書き) fs::write(path, data)
追記する OpenOptions::new().append(true).open(path)
大量書き込みを効率化 BufWriter::new(file)
コピー・削除・リネーム fs::copy / fs::remove_file / fs::rename
ディレクトリ作成 fs::create_dir_all(path)

Rustのイテレータについては「Rustのイテレータ入門:map・filter・collectの使い方」を参照してください。

Rustのエラーハンドリング(Result・Option・?)は「Rustのエラーハンドリング入門:Result・Option・?演算子の使い方」を参照してください。

RustのStringと&strの違いは「RustのStringと&strの違い:使い分けと変換方法まとめ」を参照してください。