View Source Xfile (xfile v0.4.0)

Xfile contains augmentations of the built-in File module, including the support of streams, the recursive listing of files, counting lines, grep, 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.

Displays first n lines of the file, returned as an enumerable stream.

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.

Returns the list of files in the given directory with the ability to control listing files recursively and filtering results programmatically.

Displays the last n lines of the file, returned as an enumerable stream.

Link to this section Functions

Link to this function

grep(pattern, file)

View Source (since 0.2.0)
@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 string
  • a list of strings
  • a regular expression

See String.contains?/2 for viable inputs.

Stream

Xfile.grep/2 returns its result as a Stream, so you must remember to convert it to a list via Enum.to_list/1 if you are not lazily evaluating its result.

examples

Examples

iex> Xfile.grep(~r/needle/, "path/to/file")
#Function<59.58486609/2 in Stream.transform/3>

iex> 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, "store/products.csv") |> Enum.to_list()
["215,Sprocket,9.99\n", "216,Gear,5.00\n", ...]
Link to this function

grep_rl(pattern, path, opts \\ [])

View Source (since 0.2.0)
@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.

pattern

Pattern

The given pattern can be one of the following:

  • an arity 1 function which returns a boolean; true indicates a match.
  • a string
  • a list of strings
  • a regular expression

Internally, this relies on grep/2.

Stream

Xfile.grep_rl/3 returns its result as a Stream, so you must remember to convert it to a list via Enum.to_list/1 if you are not lazily evaluating its result.

options

Options

Options are the same as those supported by ls/2. Use them to control which files are subjected to the pattern matching.

examples

Examples

iex> Xfile.grep_rl("[error]", "tmp/logs", recursive: false) |> Enum.to_list()
[
  "tmp/logs/server.1.log",
  "tmp/logs/cache.log",
  "tmp/logs/server.2.log"
]

see-also

See Also

  • grep/2 for searching a single file and returning the matching lines
  • ls/2 using the :filter option to evaluate only the names of the files.
Link to this function

head(file, n)

View Source (since 0.3.0)
@spec head(file :: Path.t(), n :: non_neg_integer()) :: Enumerable.t()

Displays first n lines of the file, returned as an enumerable stream.

examples

Examples

iex> Xfile.head(".gitignore", 3) |> Enum.to_list()
[
  "# The directory Mix will write compiled artifacts to.\n",
  "/_build/\n",
  "\n"
]
Link to this function

line_count!(file)

View Source (since 0.2.0)
@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.

examples

Examples

iex> Xfile.line_count!(".gitignore")
27
Link to this function

line_count(file)

View Source (since 0.2.0)
@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, "Invalid input"}
Link to this function

ls!(directory, opts \\ [])

View Source
@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.

Link to this function

ls(directory, opts \\ [])

View Source
@spec ls(directory :: Path.t(), opts :: Keyword.t()) ::
  {:ok, Enumerable.t()} | {:error, any()}

Returns the list of files in the given directory with the ability to control listing files recursively and filtering results programmatically.

Stream

Unlike File.ls/1, Xfile.ls/2 returns its result as a Stream, so you must remember to convert it to a list via Enum.to_list/1 if you are not lazily evaluating its result.

differences-between-file-ls-1

Differences between File.ls/1

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 (where false is equivalent to 0 and would list only the contents of the given directory). Default: true

  • :filter can be either a regular expression to be used with String.match?/2, a string or a list of strings to be used with String.contains?/2, OR an arity 1 function that receives the full file path and returns a boolean value. If the filter operation returns true, the file will be included in the output. Any other output will cause the file to be filtered from the output. Optional.

  • :show_dirs? boolean. When listing the contents of a directory that contains sub-directories and :recursive option is not true, this boolean controls whether or not the sub-directories should be included in the output (provided they pass any defined :filter). This option is ignored when :recursive is true. Setting this option to true will yield results closer to what File.ls/1 returns. Default: false.

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"
]
Link to this function

tail(file, n)

View Source (since 0.3.0)
@spec tail(file :: Path.t(), n :: non_neg_integer()) :: Enumerable.t()

Displays the last n lines of the file, returned as an enumerable stream.

examples

Examples

iex> Xfile.tail(".gitignore", 3) |> Enum.to_list()
[
  "\n",
  "# Temporary files for e.g. tests\n",
  "/tmp\n"
]