Open8

Rustファイル操作勉強スレ

Ryo24Ryo24

ファイル読み込み

use std::fs::File;
use std::io::prelude::*;

fn main() -> std::io::Result<()> {
    let mut file = File::open("foo.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    assert_eq!(contents, "Hello, world!");
    Ok(())
}

fileの中にファイルの中身の情報が入っており、read_to_string関数でcontentsの中に情報が書き込まれる。

Ryo24Ryo24
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

fn main() -> std::io::Result<()> {
    let file = File::open("foo.txt")?;
    let mut buf_reader = BufReader::new(file);
    let mut contents = String::new();
    buf_reader.read_to_string(&mut contents)?;
    assert_eq!(contents, "Hello, world!");
    Ok(())
}

バッファリングされたファイル情報を読み込みこみ、操作する。
BufReaderは小規模&複数回の呼び出しすることで処理速度を向上させる。一回で大量のデータの読み取りや数回程度のデータ読み取り読み取りでは処理速度に影響は出ない。
今回の例だとfoo.txtの中身をread_to_stringで書き出すときにopenで直接やる時より効率的にデータ読み込みがされるため、データ量が大きいファイルの場合処理速度が向上する可能性が高い。

Ryo24Ryo24

ファイルの内容を1行ずつ読み取る

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

fn main() -> Result<(), Error> {
    let path = "foo.txt";
    let input = File::open(path)?;
    let buffered = BufReader::new(input);

    for line in buffered.lines() {
        println!("{}", line?);
    }

    Ok(())
}
foo.txt
some bytes
aalkdfjlkasd
.,m.,mereiu

terminal
some bytes
aalkdfjlkasd
.,m.,mereiu

https://rust-lang-nursery.github.io/rust-cookbook/file/read-write.html#read-lines-of-strings-from-a-file

Ryo24Ryo24

ファイル書き込み

use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
    let mut buffer = File::create("foo.txt")?;

    buffer.write_all(b"some bytes")?;
    Ok(())
}

foo.txt
some bytes

ファイル作成(既存にある場合、スキップ)&some bytesの内容でファイルの中身を書き込む

Ryo24Ryo24

write function

writeはバッファーを書き込み、バイト数を返す。

use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
    let mut buffer = File::create("foo.txt")?;

    // Writes some prefix of the byte string, not necessarily all of it.
    let hoge = buffer.write(b"some bytes")?;
    println!("hoge: {}", hoge);
    Ok(())
}

terminal
hoge: 10
foo.txt
some bytes

foo.txtファイルに**some bytes(10 bytes)**を書き込み&バイト数を返す

Ryo24Ryo24
use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
    let data = b"some bytes";

    let mut pos = 0;
    let mut buffer = File::create("foo.txt")?;

    while pos < data.len() {
        let bytes_written = buffer.write(&data[pos..])?;
        pos += bytes_written;
    }
    Ok(())
}

use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
    let data = b"some bytes";

    let mut pos = 0;
    let mut buffer = File::create("foo.txt")?;
    buffer.write(data);

    Ok(())
}

二つとも結果が同じだし、違いがわからぬ
https://doc.rust-lang.org/std/io/trait.Write.html#examples

Ryo24Ryo24

writewrite_allの解説を読む限りだとどちらもバイトを書き出す処理。そしてwrite_allwriteをラップしてそうやな。
バイトデータを書き出すという目的を実現する時、特別な理由がない限りはwrite_allでいいような気がする。writeだと1回しか書き出し処理をしないため、別プロセスや違うスレッドで処理が失敗したときに バイトデータを書き出すという目的が失敗する可能性を秘めている。

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

fn main() {
    let mut fileRef = OpenOptions::new()
                        .append(true)
                        .open("foo.txt")
                        .expect("Unable to open file");   
    
    fileRef.write_all(b"some bytes\n").expect("write failed");
}

ファイルに追記する。
appendtrue指定することにより、ファイルに追記する形になる。