Crate scan_dir [] [src]

Simple interface to iterate over files or subdirs of a directory

Features:

  1. Ensure that file names are decodable to utf-8 (or error/warning is propagated)
  2. Ignore hidden entries (by default)
  3. Ignore common text editor and revision control backup files
  4. Select only files or only directories (and resolve symlinks)
  5. Simpler but detailed enough error handling
  6. Recursive directory scanner

For example you can read all subdirectories this way:

use scan_dir::ScanDir;

ScanDir::dirs().read(".", |iter| {
    for (entry, name) in iter {
        println!("File {:?} has full path {:?}", name, entry.path());
    }
}).unwrap()

Compare it to stdlib way:

use std::fs::read_dir;
for entry_res in read_dir(".").unwrap() {
    let entry = entry_res.unwrap();
    let file_name_buf = entry.file_name();
    let file_name = file_name_buf.to_str().unwrap();
    if !file_name.starts_with(".") &&
        entry.file_type().unwrap().is_dir()
    {
        println!("File {:?} has full path {:?}",
            file_name, entry.path());
    }
}

Well, it looks almost fine until you want to turn unwrap's into correct error reporting.

Here is a list of non-hidden rust files:

use scan_dir::ScanDir;

let files: Vec<_> = ScanDir::files().read(".", |iter| {
    iter.filter(|&(_, ref name)| name.ends_with(".rs"))
        .map(|(entry, _)| entry.path())
        .collect()
}).unwrap();

And when you want to to return an from the closure, you need to unify the errors somehow. For example:

use std::io;
use std::path::PathBuf;
use std::fs::File;
use scan_dir::ScanDir;

#[derive(Debug)]
enum MyError {
    Scan(scan_dir::Error),
    File(io::Error, PathBuf),
}

let result = ScanDir::files().read(".", |iter| {
    for (entry, name) in iter {
        // ensure file is accessible
        try!(File::open(entry.path())
            .map_err(|e| MyError::File(e, entry.path())));
    }
    Ok(())
}).map_err(MyError::Scan).and_then(|val| val);
println!("Error occured {:?}", result.err());

Let's see what's happen here:

  1. The return value of read() is Result<Result<(), io::Error>, MyError>
  2. map_err(MyError::Scan) turns scan_dir error into our wrapper type
  3. and_then(|val| val) unifies the error, producing Result<(), MyError>

Note in the last example you might convert error in the and_then clause, but we want to know exact file name where error occured so we store it in the error inside the lambda.

Recursive scanner works much the same, except (a) iterator yields items recursively, in depth-first order. and (b) list of errors returned instead of single error. For example:

use scan_dir::ScanDir;

let all_rs_files: Vec<_> = ScanDir::files().walk(".", |iter| {
    iter.filter(|&(_, ref name)| name.ends_with(".rs"))
        .map(|(ref entry, _)| entry.path())
        .collect()
}).unwrap();

Structs

Iter

Iterator over pairs of (DirEntry, String) where latter is the file name

ScanDir

Settings for directory walker

Walker

Iterator over pairs of (DirEntry, String) where latter is the file name

Enums

Error

Error type for scan dir