代码之家  ›  专栏  ›  技术社区  ›  saga

为什么fs::read_dir()会在Result<DirEntry,Error>

  •  0
  • saga  · 技术社区  · 5 年前

    这段代码打印了几个 Ok 在我的系统中:

    use std::fs;
    
    fn main() {
        fs::read_dir("/home").unwrap().for_each(|e| {
            println!("{:?}", e);
        });
    }
    

    我需要 unwrap 这个 DirEntry 元素,然后再使用它们。

    文件 fs::read_dir 各国:

    返回一个迭代器来遍历目录中的条目。

    迭代器将生成 io::Result<DirEntry> 。初始构造迭代器后可能会遇到新错误。

    文档中提到的是什么样的错误?安全吗 打开…的包装 这个 Result ?

    1 回复  |  直到 4 年前
        1
  •  5
  •   Frxstrem    5 年前

    fs::read_dir 打开目录时可能会遇到错误,例如,如果目录不存在或用户没有读取该目录的权限。但是,即使在打开目录后,也可能会出现任意数量的错误:

    • 该目录可能已被删除;
    • 目录的权限可能已更改;
    • 底层存储介质可能存在IO错误(例如硬盘驱动器故障);
    • 目录可能位于已删除的可移动驱动器(或已断开连接的网络驱动器)上;
    • 或操作系统可能给出的任何其他操作错误

    无法在给定的结果中返回此错误 fs::read_dir ; 相反,我们必须在迭代器本身中给出它们。这就是迭代器生成类型为 Result<DirEntry, std::io::Error> ,这样程序员就有可能捕捉并处理这些错误。


    如果安全的话 unwrap 结果是,只有确定结果不是错误(否则代码会死机)时,才是真正安全的。在许多情况下,比如原型设计时,您可能不在乎代码是否崩溃,但在编写正确的应用程序时,您应该避免生锈 打开…的包装 而是依靠正确的错误处理和错误传播。

    这是我在使用可能产生错误的迭代器时通常使用的模式:

    use std::{fs, io};
    
    fn read_dir_and_do_stuff() -> Result<(), io::Error> {
        for entry in fs::read_dir("/home")? {
            //                            ^
            //               v------------'---  automatically return errors
            let entry = entry?;
    
            // ... do something
            println!("{:?}", entry);
        }
    
        Ok(())
    }
    
    fn main() {
        if let Err(err) = read_dir_and_do_stuff() {
             // handle error
             println!("Error occurred: {}", err);
             return;
        }
    }
    

    您还可以使用以下方法: Iterator::try_fold , Iterator::try_for_each Iterator::collect::<Result<..., E>> 如果你想使用链接而不是 for in .

        2
  •  2
  •   the8472    5 年前

    快速查看引擎盖下的via strace 显示以下内容(经过一些修剪):

    $ strace ./target/debug/readdir-test
    openat(AT_FDCWD, "/home", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
    getdents64(3, /* 4 entries */, 32768)   = 104
    getdents64(3, /* 0 entries */, 32768)   = 0
    +++ exited with 0 +++
    

    因此readdir需要多个系统调用。检查 man getdents64 告诉我们这是特定于linux的,POSIX API是 readdir 它的主页上又写着:

    函数的作用是:返回一个指向dirent结构的指针,该结构表示dirp指向的目录流中的下一个目录项。到达目录流末尾或发生错误时,返回NULL。

    这告诉我们,遍历目录是分多个步骤执行的,每个步骤都可能返回一个错误。因此,将其暴露在铁锈中的正确方法正在回归 Result 每一步。