Lazily stream directory entries using the native OS directory-reading API.
Each element of the stream is a %Flier.Entries.Entry{} struct with three
fields:
:name— The entry's file name as a string (not a full path).:type— One of:file,:directory,:symlink, or:other.:path— Relative path from the walk root to the directory containing the entry. Always"."in flat (non-recursive) mode.
The stream reads entries on demand, so arbitrarily large directories can be processed without loading all entries into memory at once.
Examples
# Print every entry in /tmp
"/tmp"
|> Flier.Entries.stream()
|> Enum.each(fn entry ->
IO.puts("#{entry.name} (#{entry.type})")
end)
# Collect only regular files
files =
"/home/user/documents"
|> Flier.Entries.stream()
|> Stream.filter(fn entry -> entry.type == :file end)
|> Enum.map(& &1.name)
# Recursive walk
"/home/user/projects"
|> Flier.Entries.stream(recursive: true)
|> Stream.filter(fn entry -> entry.type == :file end)
|> Enum.map(fn entry ->
Path.expand(Path.join(["/home/user/projects", entry.path, entry.name]))
end)
Summary
Functions
@spec stream(path :: String.t(), opts :: keyword()) :: Enumerable.t()
Returns a lazy Stream of directory entries for path.
Parameters
path— Absolute or relative path to the directory to read.opts— Keyword options (see below).
Options
recursive: boolean— Whentrue, descends into subdirectories depth-first. Defaults tofalse.max_depth: non_neg_integer() | :infinity— Maximum recursion depth.0means only the entries inpathitself (equivalent to non-recursive),1meanspathplus one level of subdirectories, and so on. Only relevant whenrecursive: true. Defaults to:infinity.follow_symlinks: boolean— Whentrue, symbolic links that point to directories are descended into during a recursive walk. Whenfalse(default), symlinked directories are yielded as entries but not recursed into. Only relevant whenrecursive: true. Note: enabling this without amax_depthguard may cause infinite loops if the directory tree contains symlink cycles.on_error: :skip | :raise— Controls behaviour when a subdirectory cannot be opened (e.g. due to a permission error).:skip(default) silently continues the walk;:raiseraises aRuntimeError. Only relevant whenrecursive: true.
Returns
A lazy Stream of %Flier.Entries.Entry{} structs.
In flat mode the :path field of every entry is ".". In recursive mode
:path holds the relative path from path to the directory containing the
entry — "." for root-level entries, "subdir" for entries one level deep,
etc.
To build the full absolute path of an entry:
full = Path.expand(Path.join([root, entry.path, entry.name]))Raises if path does not exist or cannot be opened.
Examples
# Flat listing
Flier.Entries.stream("/tmp") |> Enum.to_list()
# Recursive listing
Flier.Entries.stream("/home/user", recursive: true) |> Enum.to_list()
# Recursive, limited to two levels deep
Flier.Entries.stream("/home/user", recursive: true, max_depth: 2)
|> Enum.to_list()
# Recursive, follow symlinked dirs (use max_depth to guard against cycles)
Flier.Entries.stream("/home/user", recursive: true, follow_symlinks: true, max_depth: 10)
|> Enum.to_list()
# Count entries in a directory
"/usr/bin" |> Flier.Entries.stream() |> Enum.count()