17

I can display a directory list like this:

use std::fs;

fn main() {
    let paths = fs::read_dir("./").unwrap();
    for path in paths {
        println!("Name: {}", path.unwrap().path().display())
    }
}

Can I sort the ReadDir iterator before iteration? The directory names are date-like numbers like 201610131503. I read the documentation for ReadDir but I did not find a built-in function for this. Maybe I do not know how to search?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
rap-2-h
  • 30,204
  • 37
  • 167
  • 263

3 Answers3

24

ReadDir only reads one entry at a time, so it can't sort it before iterating. There is no sorted readdir system call (at least not on the platforms I know of, which means there can't be a portable one).

So the only option is to read into a Vec and sort there:

use std::fs;

fn main() {
    let mut paths: Vec<_> = fs::read_dir("/").unwrap()
                                              .map(|r| r.unwrap())
                                              .collect();
    paths.sort_by_key(|dir| dir.path());
    for path in paths {
        println!("Name: {}", path.path().display())
    }
}
Chris Emerson
  • 13,041
  • 3
  • 44
  • 66
6

Can I sort the ReadDir iterator before iteration?

Basically, no. On macOS and Linux, the readdir_r function is used. This is not guaranteed to return in any specific order. Generally, it will return in the order that is fastest / easiest for the filesystem, which could change every time you call it.

You will need to collect the items, sort them, then re-iterate.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
-2

This is similar to the accepted answer but with a little error handling added. In most situations you would want to report an error to the user, or propagate errors to the caller in a library. I've used the answer at How do I stop iteration and return an error when Iterator::map returns a Result::Err? to collect a iterator of Results into a Result<vec<_>, _>.

I'm supplying an additional answer so others searching the same problem get something they may find more practical in a program where errors are handled.

use std::fs::{read_dir, DirEntry};
use std::io;
use std::path::Path;

fn main() {
    for path in read_dir_sorted("/").expect("IO error reading /") {
        println!("Name: {}", path.path().display())
    }
}

fn read_dir_sorted<P: AsRef<Path>>(path: P) -> Result<Vec<DirEntry>, io::Error> {
    let mut paths = read_dir(path)?
            .collect::<Result<Vec<_>, _>>()?;
    paths.sort_by_key(|de| de.file_name());
    Ok(paths)
}
AlexKing
  • 91
  • 6
  • 1
    Error handling isn't the subject of the question, and the OP explicitly didn't account for it (`.unwrap()` all over the place). If people coming here will have problems with that, they can ask a new question specifically about that. – Chayim Friedman Jun 06 '22 at 03:21
  • I think error handling is idomatic rust. Some of the biggest problems I had/have while learning rust is understanding parameter and return value types, and error handling. Often SO answers were so minimalistic I couldn't work out how to incorporate them in my code. I suggest this can be helpful (perhaps not to the original poster from ~6 years ago). Specifically it would have helped me today when this Q was the top hit in my search results. If you don't like this approach it's already at the bottom of the list; not sure my contribution deserves a downvote. – AlexKing Jun 06 '22 at 04:00
  • 1
    If you think this is useful, you can edit the accepted answer (and perhaps the question too). Doesn't mean they will be accepted; I for one would reject them. SO is about creating a quality Q&A resource. The answer is here, and error handling is noise. Of course that is my opinion, and you can think otherwise. About the downvote, generally it is discouraged to assume someone specific was the downvoter (many times it is just incorrect), but in this case this was indeed me, because I think this answer is not useful. Don't take this (or any) downvote personally. – Chayim Friedman Jun 06 '22 at 16:46
  • Well yes, I think my answer is useful. I agree my need for a sorted version of read_dir that can be used in code that handles errors is not the same as the original question, and the accepted answer already answers the original question adequately. Therefore editing both the question and answer may not be appropriate. Having an additional answer that is directly usable may help rust learners, and helps to create a quality resource. The only question is whether an almost duplicate question and answer, but specifying error handling, would be the better way to provide that. Perhaps. – AlexKing Aug 19 '22 at 23:32