Rust標準ライブラリーだけでファイルのハッシュ値を計算する

検索しても意外と見付からないのでね

Rustの標準ライブラリーだけで、ファイルのハッシュ値を計算したいことがある。ここでの目的は改ざん防止ではなくて、「このディレクトリー内のファイルで、内容の重複した物(同じ画像が複数あるとか)を検出したい」といった場合に使う物。

プログラム内でだけ、ファイル内容の同一性を計算できればいいから、その結果を他のプログラムに渡したり、ユーザーの手元で再現できたり、みたいな必要はここではない。そういうのが必要な場合は、アルゴリズムが標準化されたSHA256とかDM5とかを使うのがよくて(コマンドラインで簡単に検証できるしね)、それ用のクレートを使おう。

use std::collections::hash_map::DefaultHasher;
use std::fs::File;
use std::hash::Hasher;
use std::io::{BufReader, Read};
use std::env::args;

fn main() {
    let file_path = args().into_iter().nth(1).expect("Specify file to calculate hash");
    println!("hash for {}: {}", &file_path, calculate_file_hash(&file_path));
}

fn calculate_file_hash(file_path: &str) -> u64 {
    let file = File::open(file_path).expect("file path");
    let mut reader = BufReader::new(file);
    let mut hasher = DefaultHasher::new();
    let mut buffer = [0; 1024];

    while let Ok(n) = reader.read(&mut buffer) {
        hasher.write(&buffer);

        if n == 0 {
            break;
        }
    }

    hasher.finish()
}

cargo buildして実行すると結果が出力される。

% ./target/debug/rust-calculate-file-hash Cargo.toml
hash for Cargo.toml: 15721806948633906843
% ./target/debug/rust-calculate-file-hash Cargo.lock
hash for Cargo.lock: 15030569525137916044
% ./target/debug/rust-calculate-file-hash src/main.rs
hash for src/main.rs: 17726332095612413813