web-dev-qa-db-ja.com

Rust 1.xでファイルを読み書きする事実上の方法は何ですか?

Rustが比較的新しいので、ファイルの読み取りと書き込みの方法があまりにも多く見られました。多くは誰かが彼らのブログのために思いついた非常に厄介なスニペットであり、私が見つけた例の99%は(Stack Overflowでも)不安定なビルドのもので、もはや機能しません。 Rustが安定したので、ファイルを読み書きするためのシンプルで読みやすく、パニックのないスニペットは何ですか?

これは、テキストファイルの読み取りという点で機能するものに最も近いものですが、必要なものがすべて含まれていると確信していても、コンパイルはできません。これは、Google +で見つけたすべての場所のスニペットに基づいています。変更した唯一の点は、古いBufferedReaderBufReaderになったことです。

use std::fs::File;
use std::io::BufReader;
use std::path::Path;

fn main() {
    let path = Path::new("./textfile");
    let mut file = BufReader::new(File::open(&path));
    for line in file.lines() {
        println!("{}", line);
    }
}

コンパイラーは不平を言っています:

error: the trait bound `std::result::Result<std::fs::File, std::io::Error>: std::io::Read` is not satisfied [--explain E0277]
 --> src/main.rs:7:20
  |>
7 |>     let mut file = BufReader::new(File::open(&path));
  |>                    ^^^^^^^^^^^^^^
note: required by `std::io::BufReader::new`

error: no method named `lines` found for type `std::io::BufReader<std::result::Result<std::fs::File, std::io::Error>>` in the current scope
 --> src/main.rs:8:22
  |>
8 |>     for line in file.lines() {
  |>                      ^^^^^

要約すると、私が探しているのは:

  • 簡潔
  • 読みやすさ
  • 考えられるすべてのエラーをカバー
  • パニックにならない
99
Jared

ここで示す関数はどれも単独でパニックすることはありませんが、アプリケーションに最適なエラー処理の種類がわからないため、expectを使用しています。読むRustプログラミング言語エラー処理の章 で障害を適切に処理する方法を理解する独自のプログラム。

Rust 1.26以降

基礎となる詳細を気にしたくない場合は、読み取りおよび書き込み用の1行の関数があります。

Stringにファイルを読み取ります

use std::fs;

fn main() {
    let data = fs::read_to_string("/etc/hosts").expect("Unable to read file");
    println!("{}", data);
}

ファイルをVec<u8>として読み取ります

use std::fs;

fn main() {
    let data = fs::read("/etc/hosts").expect("Unable to read file");
    println!("{}", data.len());
}

ファイルを書く

use std::fs;

fn main() {
    let data = "Some data!";
    fs::write("/tmp/foo", data).expect("Unable to write file");
}

Rust 1.0以降

これらの形式は、StringまたはVecを割り当てる1行関数よりも少し冗長ですが、割り当てられたデータを再利用したり、既存のオブジェクトに追加したりできるという点でより強力です。

データを読む

ファイルの読み取りには、2つのコア部分 File および Read が必要です。

Stringにファイルを読み取ります

use std::fs::File;
use std::io::Read;

fn main() {
    let mut data = String::new();
    let mut f = File::open("/etc/hosts").expect("Unable to open file");
    f.read_to_string(&mut data).expect("Unable to read string");
    println!("{}", data);
}

ファイルをVec<u8>として読み取ります

use std::fs::File;
use std::io::Read;

fn main() {
    let mut data = Vec::new();
    let mut f = File::open("/etc/hosts").expect("Unable to open file");
    f.read_to_end(&mut data).expect("Unable to read data");
    println!("{}", data.len());
}

ファイルを書く

ファイルの書き込みも同様です。ただし、 Write 特性を使用し、常にバイトを書き込みます。 &str を使用すると、String/as_bytesをバイトに変換できます。

use std::fs::File;
use std::io::Write;

fn main() {
    let data = "Some data!";
    let mut f = File::create("/tmp/foo").expect("Unable to create file");
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

バッファI/O

ファイルから直接読み取るのではなく、BufReaderBufWriterを使用するコミュニティのプッシュを少し感じました

バッファー付きリーダー(またはライター)は、バッファーを使用してI/O要求の数を減らします。たとえば、ディスクに256回アクセスする代わりに、ディスクに1回アクセスして256バイトを読み取る方がはるかに効率的です。

そうは言っても、ファイル全体を読むときに、バッファ付きのリーダー/ライターが役立つとは思わない。 read_to_end はやや大きなチャンクでデータをコピーしているように見えるため、転送はすでにより少ないI/O要求に自然に結合されている可能性があります。

読み取りに使用する例を次に示します。

use std::fs::File;
use std::io::{BufReader, Read};

fn main() {
    let mut data = String::new();
    let f = File::open("/etc/hosts").expect("Unable to open file");
    let mut br = BufReader::new(f);
    br.read_to_string(&mut data).expect("Unable to read string");
    println!("{}", data);
}

そして書くために:

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

fn main() {
    let data = "Some data!";
    let f = File::create("/tmp/foo").expect("Unable to create file");
    let mut f = BufWriter::new(f);
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

BufReaderは、行ごとに読みたい場合に便利です。

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

fn main() {
    let f = File::open("/etc/hosts").expect("Unable to open file");
    let f = BufReader::new(f);

    for line in f.lines() {
        let line = line.expect("Unable to read line");
        println!("Line: {}", line);
    }
}
140
Shepmaster