File_Utilities module

visit_files

procedure · 1 overloadSource

Calls proc with user_data for each entry of the directory dir_name, and returns true if every entry could be examined. With recursive the walk goes into sub-directories too.

visit_files :: (
    dir_name: string,
    recursive: bool,
    user_data: $T,
    proc: (info: *File_Visit_Info, user_data: T),
    visit_files := true,
    visit_directories := false,
    visit_symlinks := true,
    follow_directory_symlinks := true
) -> bool
  • The order is the file system's and is not sorted. . and .. are skipped.
  • visit_files, visit_directories and visit_symlinks pick what proc hears about. A link counts as a link whatever it points at, so with visit_symlinks off it is never reported as a file or a directory.
  • A directory is entered whether or not it is reported. proc can stop that by setting info.descend_into_directory to false, which needs visit_directories so that proc sees the directory.
  • follow_directory_symlinks decides whether links to directories are entered. A directory that is already being walked further up is not entered again, so link cycles end. Two different paths to one directory are both walked.
  • info and its strings are valid only during the call. A link whose target is missing is reported as a link, with the details of the link itself.

A missing or unreadable dir_name returns false without calling proc. An entry whose details cannot be read is reported with had_error set and makes the result false, but the walk goes on.

Parameters

dir_name: string
recursive: bool
user_data: $T
proc: (info: *File_Visit_Info, user_data: T)
visit_files := true
visit_directories := false
visit_symlinks := true
follow_directory_symlinks := true

Returns

bool
ExampleOpen in playground ↗
#import "Extensions/Environment";
#import "File";
base := environment_variable("TMPDIR");
if base == "" base = environment_variable("TEMP");
if base == "" base = "/tmp";
root := tprint("%/jai-doc-visit-files", base);
defer {
    file_delete(tprint("%/top", root));
    file_delete(tprint("%/sub/leaf", root));
    delete_directory(tprint("%/sub", root));
    delete_directory(root);
}

assert(make_directory_if_it_does_not_exist(tprint("%/sub", root), recursive = true));
assert(write_entire_file(tprint("%/top", root), "top"));
assert(write_entire_file(tprint("%/sub/leaf", root), "leaf"));

Count :: struct {
    files: int;
    directories: int;
    bytes: s64;
}
count: Count;
tally :: (info: *File_Visit_Info, count: *Count) {
    if info.is_directory count.directories += 1;
    else {
        count.files += 1;
        count.bytes += info.size;
    }
}

assert(visit_files(root, true, *count, tally, visit_directories = true));
assert(count.files == 2 && count.directories == 1 && count.bytes == 7);

count = .{};
assert(visit_files(root, false, *count, tally)); // top level only
assert(count.files == 1);
assert(!visit_files(tprint("%/missing", root), false, *count, tally));

See also