View Source Xfile (xfile v0.2.0)
Xfile
contains augmentations of the built-in File
module, such as supporting
streams, recursion, and programmatic filtering.
Link to this section Summary
Functions
Like the venerable command-line utility, grep
searches lines in the given file
using the given pattern, returning only the matching lines as a stream.
This function mimics the functionality of grep -rl
: it recursively searches
all files in the given path, returning only a list of file names (i.e. paths)
whose contents have one or more lines that match the pattern.
As Xfile.line_count/1
, but returns raw results on success or raises on :error
.
Counts the number of lines in the given file, offering functionality similar to wc -l
.
Directories are not allowed. This is just some sugar around File.stream!/1
.
As Xfile.ls/2
, but returns raw results on success or raises on :error
.
Like File.ls/1
, this returns the list of files in the given directory, but it
makes available some useful options to support recursive listing and filtering
results programmatically.
Link to this section Functions
@spec grep(pattern :: String.pattern() | (String.t() -> boolean()), file :: Path.t()) :: Enumerable.t()
Like the venerable command-line utility, grep
searches lines in the given file
using the given pattern, returning only the matching lines as a stream.
The given pattern can be one of the following:
- an arity 1 function which returns a boolean;
true
indicates a match. - a pattern compatible with
String.contains?/2
, i.e. a string, a list of strings, or a regular expression.
Stream
Xfile.grep/2
returns its result as aStream
, so you must remember to convert it to a list viaEnum.to_list/1
if you are not lazily evaluating its result.
examples
Examples
iex(1)> Xfile.grep(~r/needle/, "path/to/file")
#Function<59.58486609/2 in Stream.transform/3>
iex(1)> Xfile.grep("dir", ".gitignore") |> Enum.to_list()
["# The directory Mix will write compiled artifacts to.\n",
"# The directory Mix downloads your dependencies sources to.\n"]
Using a function to evaluate file lines:
iex> f = fn line ->
[serial_number, _] = String.split(line, " ")
String.to_integer(num) > 214
end
iex> Xfile.grep(f, "file/w/line-numbers") |> Enum.to_list()
["215 Sprocket\n", "216 Gear\n", ...]
@spec grep_rl(pattern :: String.pattern(), path :: Path.t(), opts :: Keyword.t()) :: Enumerable.t()
This function mimics the functionality of grep -rl
: it recursively searches
all files in the given path, returning only a list of file names (i.e. paths)
whose contents have one or more lines that match the pattern.
Internally, this relies on grep/2
.
Stream
Xfile.grep_rl/3
returns its result as aStream
, so you must remember to convert it to a list viaEnum.to_list/1
if you are not lazily evaluating its result.
see-also
See Also
@spec line_count!(file :: Path.t()) :: non_neg_integer() | none()
As Xfile.line_count/1
, but returns raw results on success or raises on :error
.
@spec line_count(file :: Path.t()) :: {:ok, non_neg_integer()}
Counts the number of lines in the given file, offering functionality similar to wc -l
.
Directories are not allowed. This is just some sugar around File.stream!/1
.
Newlines
This function technically counts new lines, which may result in "off-by-one" errors when the last line of a file is not terminated with a newline.
examples
Examples
iex> Xfile.line_count(".gitignore")
{:ok, 27}
iex> Xfile.line_count("/tmp"}
{:error, :directory}
@spec ls!(directory :: Path.t(), opts :: Keyword.t()) :: Enumerable.t() | none()
As Xfile.ls/2
, but returns raw results on success or raises on :error
.
@spec ls(directory :: Path.t(), opts :: Keyword.t()) :: {:ok, Enumerable.t()} | {:error, any()}
Like File.ls/1
, this returns the list of files in the given directory, but it
makes available some useful options to support recursive listing and filtering
results programmatically.
Stream
Unlike
File.ls/1
,Xfile.ls/2
returns its result as aStream
, so you must remember to convert it to a list viaEnum.to_list/1
if you are not lazily evaluating its result.
differences-between-file-ls-1
Differences between File.ls/1
Xfile.ls/2
returns results as aStream
Xfile.ls/2
returns full paths (relative or absolute) instead of just basenames.
options
Options
:recursive
indicates whether the directory and its subdirectories should be recursively searched. This can be expressed either as a simple boolean or as a positive integer indicating the maximum depth (wherefalse
is equivalent to0
and would list only the contents of the given directory). Default:true
:filter
can be either a regular expression to be used withString.match?/2
OR an arity 1 function that receives the full file path and returns a boolean value. If the filter operation returnstrue
, the file will be included in the output. Any other output will cause the file to be filtered from the output. Optional.
examples
Examples
Use a regular expression to return only .txt
files:
iex> {:ok, stream} = Xfile.ls("path/to/files", filter: ~r/\.txt$/)
{:ok, #Function<59.58486609/2 in Stream.transform/3>}
iex> Enum.to_list(stream)
[
"path/to/files/a.txt",
"path/to/files/b.txt",
"path/to/files/subdir/c.txt"
]
Use a function to apply more complex logic to filter the results:
iex> {:ok, stream} = Xfile.ls("mydir", filter: fn x ->
stat = File.stat!(x)
stat.size > 1024
end)
{:ok, #Function<59.58486609/2 in Stream.transform/3>}
iex> Enum.to_list(stream)
[
"mydir/big-file",
"mydir/big-file2",
# ...
]
Limit the depth of the recursion to the given directory and its subdirectories, but no further:
iex> {:ok, stream} = Xfile.ls("top/dir", recursive: 1)
{:ok, #Function<59.58486609/2 in Stream.transform/3>}
iex> Enum.to_list(stream)
[
"top/dir/a",
"top/dir/b",
# ...
"top/dir/sub1/x",
"top/dir/sub1/y"
]