English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

RustのファイルとIO

本章では Rust 言語の I/O 操作。

コマンドラインパラメータの受け取り

コマンドラインプログラムは、コンピュータープログラムの最も基本的な存在形式であり、ほぼすべてのオペレーティングシステムがコマンドラインプログラムをサポートし、可視化プログラムの実行はコマンドラインメカニズムに基づいています。

コマンドラインプログラムは、コマンドライン環境からのパラメータを受け取ることができなければなりません。これらのパラメータは、通常、コマンドラインの命令の後にスペースで区切られています。

多くの言語(Java や C など)/C++環境パラメータは、メイン関数のパラメータ(たいていは文字列の配列)としてプログラムに渡されますが、Rust ではメイン関数は引数のない関数です。環境パラメータは開発者が std::env モジュールを使用して取得する必要があり、そのプロセスは非常に簡単です:

fn main() {
    let args = std::env::args();
    println!("{:?}", args);
}

今度はプログラムを直接実行します:

Args { inner: ["D:\\rust\\greeting\\target\\debug\\greeting.exe"] }

もしかすると、もっと長い結果が得られるかもしれませんが、これは普通のことです。この結果には、Args 構造体に inner 配列がありますが、その中にはユニークな文字列が含まれており、現在実行中のプログラムの場所を表しています。

このデータ構造は理解しにくいですが、簡単に巡回できます:

fn main() {
    let args = std::env::args();
    for arg in args {
        println!("{}", arg);
    }
}

実行結果:

D:\rust\greeting\target\debug\greeting.exe

一般的に、パラメータは巡回されるために使われますが、そうでしょうか。

今度は長く触れていない launch.json を開き、「args」[]を見つけ、ここで実行時のパラメータを設定できます。それを「args」[「first」、「second」]に書き換え、保存して先ほどのプログラムを再度実行します。実行結果:

D:\rust\greeting\target\debug\greeting.exe
first
second

本番、実際のコマンドラインプログラムとして使ったことはありません。言語のトレーニングのためには、コマンドラインで Rust プログラムを実行する方法について説明は含まれていません。しかし、訓練された開発者であれば、実行ファイルの場所を見つけ、そのディレクトリにアクセスしてコマンドラインコマンドを使用してプログラムがコマンドライン環境パラメータを受け取るかテストすることができます。

コマンドライン入力

前の章では、コマンドライン出力を使用する方法について詳細に説明しました。これは言語学習のために行われましたが、出力がないとプログラムをデバッグすることができません。しかし、コマンドラインから入力情報を取得することは、コマンドラインプログラムにとって非常に重要です。

Rustでは、std::ioモジュールは標準入力(コマンドライン入力と考えられます)に関連する機能を提供します:

use std::io::stdin;
fn main() {
let mut str_buf = String::new();
    stdin().read_line(&mut str_buf)
        .expect("Failed to read line.");
    println!("Your input line is \n{}", str_buf);
}

VSCode環境をコマンドライン入力に対応させることは非常に複雑な作業であり、プラットフォーム間の問題やデバッグ不可能な問題が関連しています。したがって、私たちは直接VSCodeのターミナルでプログラムを実行します。コマンドラインで実行します:

D:\rust\greeting> cd ./target/debug
D:\rust\greeting\target\debug> ./greeting.exe
w3codebox
入力行は以下の通りです 
w3codebox

std::io::Stdioにはread_lineメソッドが含まれており、一行の文字列をバッファに読み込むことができます。返り値はすべてResult列挙型であり、読み込み中に発生するエラーを伝達するために使用されます。したがって、expectやunwrap関数を使用してエラーを処理することが一般的です。

注意:現在、Rustの標準ライブラリには、直接コマンドラインから数字やフォーマットされたデータを読み込む方法は提供されていません。私たちは一行の文字列を読み込んで、文字列認識関数を使用してデータを処理することができます。

ファイル読み込み

私たちはコンピュータのD:\ディレクトリ下にファイルtext.txtを作成し、以下の内容です:

これはテキストファイルです。

これはテキストファイルの内容を読み込む文字列にプログラムです:

use std::fs;
fn main() {
    let text = fs::read_to_string("D:\\text.txt").unwrap();
    println!("{}", text);
}

実行結果:

これはテキストファイルです。

Rustでメモリが収容できる一つのファイル全体を読み込むことは非常に簡単です。std::fsモジュールのread_to_stringメソッドを使えば、テキストファイルの読み込みを簡単にできます。

読み込むファイルがバイナリファイルである場合、std::fs::read関数を使用して読み込むことができます u8 型集合:

use std::fs;
fn main() {
    let content = fs::read("D:\\text.txt").unwrap();
    println!("{:?}", content);
}

実行結果:

[84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 120, 116, 32, 102, 105, 108, 101, 46]

以上の二つの方法は一括読み取りであり、Webアプリケーションの開発には非常に適しています。しかし、一些底層プログラムでは、伝統的なストリーム読み取り方式はまだ置き換えられません。なぜなら、多くの場合、ファイルのサイズはメモリ容量を大幅に超える可能性があるからです。

Rustのファイルストリーム読み取り方式:

use std::io::prelude::*;
use std::fs;
fn main() {
    let mut buffer = [0u8; 5];
    let mut file = fs::File::open("D:\\text.txt").unwrap();
    file.read(&mut buffer).unwrap();
    println!("{:?}", buffer);
    file.read(&mut buffer).unwrap();
    println!("{:?}", buffer);
}

実行結果:

[84, 104, 105, 115, 32] 
[105, 115, 32, 97, 32]

std::fsモジュールのFileクラスはファイルを表すクラスであり、ファイルをオープンするために使用できます。ファイルをオープンした後、Fileのreadメソッドを使用して、バッファー(バッファーはu)にファイルの以下のいくつかのバイトを読み取ることができます。8 配列),読み込んだバイト数はバッファーの長さに等しいです。

注意:VSCodeは現在まだ標準ライブラリの参照を自動的に追加する機能がありません。したがって、「関数やメソッドが存在しない」といったエラーが発生する場合には、標準ライブラリの参照の問題が考えられます。私たちは標準ライブラリのコメントドキュメント(マウスを合わせると表示される)を確認して、手動で標準ライブラリを追加することができます。

std::fs::Fileのopenメソッドは「読み取り専用」でファイルをオープンし、対応するcloseメソッドはありません。なぜなら、Rustコンパイラはファイルが使用されなくなったときに自動的にファイルを閉じることができるからです。

ファイル書き込み

ファイル書き込みは一括書き込みとストリーム書き込みの二種類に分けられます。ストリーム書き込みはファイルをオープンする必要があり、オープン方法は「新規作成」(create)と「追加」(append)の二種類があります。

一括書き込み:

use std::fs;
fn main() {
    fs::write("D:\\text.txt", "FROM RUST PROGRAM")
        .unwrap();
}

これは一括読み込みと同じように簡単で便利です。プログラムを実行すると、D:\text.txtファイルの内容がFROM RUST PROGRAMに書き換えられます。したがって、一括書き込みは慎重に行ってください!なぜなら、ファイルの内容は直接削除されるからです(ファイルがどれだけ大きくなったとしても)。ファイルが存在しない場合は、ファイルを作成します。

ファイルの内容をストリームの方式で書き込む場合は、std::fs::Fileのcreateメソッドを使用できます:

use std::io::prelude::*;
use std::fs::File;
fn main() {
    let mut file = File::create("D:\\text.txt").unwrap();
    file.write(b"FROM RUST PROGRAM").unwrap();
}

このプログラムは前のプログラムと等価です。

注意:オープンしたファイルは、Fileのメソッドを使用するために可変な変数に保存されている必要があります!

Fileクラスにはappend静的メソッドが存在しませんが、OpenOptionsを使用して特定のメソッドでファイルを開くことができます:

use std::io::prelude::*;
use std::fs::OpenOptions;
fn main() -> std::io::Result<()> {
    
    let mut file = OpenOptions::new()
            .append(true).open("D:\\text.txt")?;
    file.write(b" APPEND WORD")?;
    Ok(())
}

実行すると、D:\text.txtファイルの内容は次のようになります:

FROM RUST PROGRAM APPEND WORD

OpenOptionsは、ファイルを開くための柔軟な方法であり、追加権限以外に読み取り権限と書き込み権限を設定できます。読み取り書き込み権限でファイルを開きたい場合は、以下のように書くことができます:

use std::io::prelude::*;
use std::fs::OpenOptions;
fn main() -> std::io::Result<()> {
    
    let mut file = OpenOptions::new()
            .read(true).write(true).open("D:\\text.txt")?;
    file.write(b"COVER")?;
    Ok(())
}

実行すると、D:\text.txtファイルの内容は次のようになります:

COVERRUST PROGRAM APPEND WORD