在Rust中判断两个文件内容是否相同

在Rust中判断两个文件内容是否相同,意外地并不好写。

这里记录了一个函数,未来用到时复制。 并且还展示了一些文件操作,以便参考。

一个函数

use std::{
    fs::File,
    io::BufReader,
    path::Path,
};

fn is_same_file(one: impl AsRef<Path>, another: impl AsRef<Path>) -> bool {
    if let (Ok(file0), Ok(file1)) = (File::open(one), File::open(another)) {
        let mut reader0 = BufReader::new(file0);
        let mut reader1 = BufReader::new(file1);
        let mut buf0 = [0u8; 256];
        let mut buf1 = [0u8; 256];
        while let (Ok(n0), Ok(n1)) = (reader0.read(&mut buf0), reader1.read(&mut buf1)) {
            if n0 != n1 {
                return false;
            }
            if n0 == 0 {
                return true;
            }
            if buf0 != buf1 {
                return false;
            }
        }
    }
    return false;
}

以上代码,有几个要点,基本已做到了比较极致的优化:

  1. 不存在,或读不了的文件,直接返回false
  2. 判断内容的buffer仅有256的长度(可调),内存开销小,false返回更快。
  3. 先判断长度、再判断内容。 BufReader::read在结束时,长度会小于256。 如果读出长度n0 != n1,则说明其中一个提前结束。
  4. 当两个文件内容都比对完后,则返回true。 一个已经读完的文件,再读则长度为0。 如果n0 == n1 == 0,则说明两个文件已经比对完成,完全相等。

一个库

如果不介意为了这个简单功能,加一个库的话,可以用same-file

use same_file::is_same_file;

fn main() {
    assert!(is_same_file("/bin/sh", "/usr/bin/sh").unwrap());
}

其它

一个文件,除了文件内容,还有文件信息,如文件名、权限、修改时间等。 这些在以上方案中,都不在比对范围内,有需要则必须单独比对。

此外,还有一些间接比对文件内容的方案,比方说,比较两个文件的SHA256。 这效率不高,但在某些特殊场景,可能会更方便。


相关笔记