Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

I/O

ロック

Rust の print! マクロと println! マクロは、呼び出しごとに stdout をロックします。これらのマクロを繰り返し呼び出す場合は、stdout を手動でロックした方がよいことがあります。

たとえば、次のコードを変更します:

#![allow(unused)]
fn main() {
let lines = vec!["one", "two", "three"];
for line in lines {
    println!("{}", line);
}
}

次のようにします:

#![allow(unused)]
fn main() {
fn blah() -> Result<(), std::io::Error> {
let lines = vec!["one", "two", "three"];
use std::io::Write;
let mut stdout = std::io::stdout();
let mut lock = stdout.lock();
for line in lines {
    writeln!(lock, "{}", line)?;
}
// `lock` がドロップされると stdout のロックが解除される
Ok(())
}
}

stdin と stderr も同様に、それらに対して繰り返し操作を行う場合はロックできます。

バッファリング

Rust のファイル I/O はデフォルトではバッファリングされません。ファイルやネットワークソケットに対して、小さな読み取りまたは書き込み呼び出しを何度も繰り返す場合は、BufReader または BufWriter を使用してください。これらは入力と出力用にメモリ内バッファを保持し、必要なシステムコールの回数を最小限に抑えます。

たとえば、次のバッファリングされていない writer コードを変更します:

#![allow(unused)]
fn main() {
fn blah() -> Result<(), std::io::Error> {
let lines = vec!["one", "two", "three"];
use std::io::Write;
let mut out = std::fs::File::create("test.txt")?;
for line in lines {
    writeln!(out, "{}", line)?;
}
Ok(())
}
}

次のようにします:

#![allow(unused)]
fn main() {
fn blah() -> Result<(), std::io::Error> {
let lines = vec!["one", "two", "three"];
use std::io::{BufWriter, Write};
let mut out = BufWriter::new(std::fs::File::create("test.txt")?);
for line in lines {
    writeln!(out, "{}", line)?;
}
out.flush()?;
Ok(())
}
}

例 1, 例 2.

明示的な flush の呼び出しは厳密には必要ありません。out がドロップされると、自動的に flush が行われるためです。しかし、その場合 flush 時に発生したエラーは無視されます。一方、明示的に flush すれば、そのエラーが明示的になります。

バッファリングを忘れることは、書き込み時によく起こります。バッファリングされていない writer とバッファリングされた writer はどちらも Write トレイトを実装しているため、バッファリングされていない writer へ書き込むコードとバッファリングされた writer へ書き込むコードはほとんど同じです。対照的に、バッファリングされていない reader は Read トレイトを実装していますが、バッファリングされた reader は BufRead トレイトを実装しています。つまり、バッファリングされていない reader から読み取るコードとバッファリングされた reader から読み取るコードは異なります。たとえば、バッファリングされていない reader でファイルを 1 行ずつ読み取るのは難しいですが、バッファリングされた reader では BufRead::read_line または BufRead::lines を使用することで簡単にできます。このため、writer について上で示したような、変更前と変更後が非常によく似ている reader の例を書くのは困難です。

最後に、バッファリングは stdout でも機能することに注意してください。そのため、stdout に対して多数の書き込みを行う場合は、手動ロックバッファリングを組み合わせるとよいかもしれません。

ファイルから行を読み取る

このセクションでは、BufRead を使用してファイルを 1 行ずつ読み取る際に、過剰なアロケーションを避ける方法を説明します。

入力を生バイトとして読み取る

組み込みの String 型は内部的に UTF-8 を使用しているため、入力を読み込む際に UTF-8 検証による小さいながらもゼロではないオーバーヘッドが発生します。UTF-8 を気にせず入力バイトを処理したいだけの場合(たとえば ASCII テキストを扱う場合)は、BufRead::read_until を使用できます。

バイト指向のデータ行を読み取るための専用クレートや、バイト文字列を扱うための専用クレートもあります。