File Paths in Elixir

The Path module in Elixir provides functions to parse and construct file paths in a way that is portable between operating systems.

defmodule FilePaths do
  def main do
    # Path.join/1 should be used to construct paths in a
    # portable way. It takes a list of path segments
    # and constructs a hierarchical path from them.
    p = Path.join(["dir1", "dir2", "filename"])
    IO.puts("p: #{p}")

    # You should always use Path.join/1 instead of
    # concatenating "/" manually. In addition to providing
    # portability, Path.join/1 will also normalize paths
    # by removing superfluous separators and directory changes.
    IO.puts(Path.join(["dir1//", "filename"]))
    IO.puts(Path.join(["dir1/../dir1", "filename"]))

    # Path.dirname/1 and Path.basename/1 can be used to split
    # a path to the directory and the file.
    IO.puts("Dir(p): #{Path.dirname(p)}")
    IO.puts("Base(p): #{Path.basename(p)}")

    # We can check whether a path is absolute.
    IO.puts(Path.type("dir/file"))
    IO.puts(Path.type("/dir/file"))

    filename = "config.json"

    # Some file names have extensions following a dot. We
    # can split the extension out of such names with Path.extname/1.
    ext = Path.extname(filename)
    IO.puts(ext)

    # To find the file's name with the extension removed,
    # use Path.rootname/1.
    IO.puts(Path.rootname(filename))

    # Path.relative_to/2 finds a relative path between a base and a
    # target. It returns the target if it cannot be made relative to base.
    rel = Path.relative_to("a/b/t/file", "a/b")
    IO.puts(rel)

    rel = Path.relative_to("a/c/t/file", "a/b")
    IO.puts(rel)
  end
end

FilePaths.main()

To run the program:

$ elixir file_paths.exs
p: dir1/dir2/filename
dir1/filename
dir1/filename
Dir(p): dir1/dir2
Base(p): filename
relative
absolute
.json
config
t/file
a/c/t/file

In this Elixir version:

  1. We use the Path module instead of filepath.
  2. Path.join/1 is used instead of filepath.Join. It takes a list of path segments.
  3. Path.dirname/1 and Path.basename/1 are used instead of filepath.Dir and filepath.Base.
  4. Path.type/1 is used instead of filepath.IsAbs. It returns :absolute or :relative.
  5. Path.extname/1 is used instead of filepath.Ext.
  6. Path.rootname/1 is used instead of strings.TrimSuffix.
  7. Path.relative_to/2 is used instead of filepath.Rel. It doesn’t return an error, but instead returns the target path if it can’t be made relative.

Elixir’s Path module provides similar functionality to Go’s filepath package, making it easy to work with file paths in a cross-platform manner.