Rustでエラーが出てないのにファイルに書き出せないときは
κeenです。随分前から書こうと思いつつ先送りになっていた小ネタです。
例えばカレントディレクトリにあるsome_file.txt
に適当なデータを書き込もうとして、以下のようなコードを書いたとします。
use std::fs::File;
use std::io::prelude::*;
use std::io::BufWriter;
fn main() {
let file = File::open("some_file.txt").unwrap();
let mut w = BufWriter::new(file);
// unwrapを呼んで書き込みエラーを検知
write!(w, "hello").unwrap();
}
これを実行してみましょう。
$ rustc write_file.rs
$ ./write_file
特段エラーは出ません。しかしながらsome_file.txt
の中身は特に書き変わっていません。
$ cat some_file.txt
$
これ、パッと原因分かりますか?
直接の原因はFile::open
です。File::open
はリードオンリーでファイルを開くのでFile::open
で開いたファイルに書き込もうとしても書き込めません(書き込みたいならFile::create
を使います)。
じゃあなぜエラーが出ないかというとBufWriter
のせいです。
書き込んだ文字列"hello"
は短いのでwrite!
を発効した時点ではまだデータはバッファに書き込まれるだけです。
このときにはまだエラーは出ません。
そしてmain
の末尾でw
のライフタイムが終わるときにBufWrite
のdrop
が呼ばれますが、ここではエラーが無視されるのでユーザにはエラーが起きてないように見える訳です。
このような事故を防ぐために以下のようにflush
を呼びましょう。
use std::fs::File;
use std::io::prelude::*;
use std::io::BufWriter;
fn main() {
let file = File::open("some_file.txt").unwrap();
let mut w = BufWriter::new(file);
// unwrapを呼んで書き込みエラーを検知
write!(w, "hello").unwrap();
// flushを呼ぶことで書き込みエラーを全て拾える
w.flush().unwrap();
}
$ rustc write_file.rs
$ ./write_file
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 9, message: "Bad file descriptor" } }', /checkout/src/libcore/result.rs:859
note: Run with `RUST_BACKTRACE=1` for a backtrace.