filename(3)

πŸ“¦
version 29.0.6 Β· 3 versions
, in ubuntu stonking

🌸 filename β€” the manual, bestie πŸ’…

okay so this is filename(3) from the Erlang Module Definition collection. pull up a chair, grab a boba, we're doing filenames today and honestly? it's giving ✨foundational✨.


✨ NAME ✨

filename β€” Filename manipulation functions. that's it, that's the whole job. πŸŽ€


πŸ¦‹ DESCRIPTION πŸ¦‹

So this module gives you functions for analyzing and manipulating filenames. And the whole point of how it's built is that your Erlang code can keep it moving across so many different platforms with totally different filename formats. no cap.

When we say "filename" here, we mean all strings that can be used to denote a file. That could be:

  • a lil short relative name like foo.erl
  • a whole long absolute name including a drive designator
  • a directory name like D:\usr/local\bin\erl/lib\tools\foo.erl
  • or literally any variation in between πŸ’€

On Windows, all functions return filenames with forward slashes only, even if the arguments you fed them contain backslashes. If you wanna normalize a filename by removing redundant directory separators, use join/1. that's the move. 🫢

The module also supports raw filenames, in the way that if a binary is present, or the filename can't be interpreted according to the return value of file:native_name_encoding/0, a raw filename is also returned. like for example, join/1 provided with a path component that is a binary (and can't be interpreted under the current native filename encoding) results in a raw filename that gets returned β€” and yes, the join operation is still performed, of course it is bestie. For more info about raw filenames, peep the file module. πŸ“š

NOTE: Functionality in this module generally assumes valid input and does not necessarily fail on input that does not use a valid encoding, but may instead very likely produce invalid output. File operations used to accept filenames containing null characters (integer value zero). This caused the name to be truncated and in some cases arguments to primitive operations to get mixed up. Filenames containing null characters inside the filename are now rejected and will cause primitive file operations to fail. 🚫
WARNING: Currently null characters at the end of the filename will be accepted by primitive file operations. Such filenames are however still documented as invalid. The implementation will also change in the future and reject such filenames. so like, don't get comfy with that. ⚠️

πŸ’œ DATA TYPES πŸ’œ

the little type girlies, absolutely iconic, let's go:

basedir_opts() ::
          #{author => string() | binary(),
            os => windows | darwin | linux,
            version => string() | binary()}.
basedir_path_type() ::
          user_cache | user_config | user_data | user_log.

basedir_paths_type() :: site_config | site_data.

πŸ”₯ FUNCTIONS πŸ”₯

absname(Filename) -> file:filename_all() when Filename :: file:name_all().

Converts a relative Filename and returns an absolute name. And listen β€” no attempt is made to create the shortest absolute name, because that could give you incorrect results on file systems that allow links. so we're not doing that. periodt.

Unix examples, slay:

1> pwd().
"/usr/local"
2> filename:absname("foo").
"/usr/local/foo"
3> filename:absname("../x").
"/usr/local/../x"
4> filename:absname("/").
"/"

Windows examples, also slay:

1> pwd().
"D:/usr/local"
2> filename:absname("foo").
"D:/usr/local/foo"
3> filename:absname("../x").
"D:/usr/local/../x"
4> filename:absname("/").
"D:/"

absname(Filename, Dir) -> file:filename_all() when Filename :: file:name_all(), Dir :: file:name_all().

Same as absname/1, except the directory that the filename is to be made relative to is specified in argument Dir. you get to pick the vibe check location yourself. πŸ’–


absname_join(Dir, Filename) -> file:filename_all() when Dir :: file:name_all(), Filename :: file:name_all().

Joins an absolute directory with a relative filename. 🧚

Similar to join/2, but on platforms with tight restrictions on raw filename length and no support for symbolic links, leading parent directory components in Filename are matched against trailing directory components in Dir so they can be removed from the result β€” minimizing its length. look at her, optimizing. πŸ‘‘


basedir(PathType, Application) -> file:filename_all() when PathType :: basedir_path_type(), Application :: string() | binary(); (PathsType, Application) -> [file:filename_all()] when PathsType :: basedir_paths_type(), Application :: string() | binary().

Equivalent to basedir(PathType, Application, #{}) or basedir(PathsType, Application, #{}). πŸ’«


basedir(PathType, Application, Opts) -> file:filename_all() when PathType :: basedir_path_type(), Application :: string() | binary(), Opts :: basedir_opts(); (PathsType, Application, Opts) -> [file:filename_all()] when PathsType :: basedir_paths_type(), Application :: string() | binary(), Opts :: basedir_opts().

Returns a suitable path, or paths, for a given type. πŸ“

If os is not set in Opts, the function defaults to the native option β€” that is 'linux', 'darwin' or 'windows', as understood by os:type/0. Anything not recognized as 'darwin' or 'windows' gets interpreted as 'linux'. simple as.

The options 'author' and 'version' are only used with 'windows' option mode. iykyk.

  • user_cache

The path location is intended for transient data files on a local machine.

  • On Linux: Respects the os environment variable XDG_CACHE_HOME.
1> filename:basedir(user_cache, "my_application", #{os=>linux}).
"/home/otptest/.cache/my_application"
  • On Darwin:
1> filename:basedir(user_cache, "my_application", #{os=>darwin}).
"/home/otptest/Library/Caches/my_application"
  • On Windows:
1> filename:basedir(user_cache, "My App").
"c:/Users/otptest/AppData/Local/My App/Cache"
2> filename:basedir(user_cache, "My App").
"c:/Users/otptest/AppData/Local/My App/Cache"
3> filename:basedir(user_cache, "My App", #{author=>"Erlang"}).
"c:/Users/otptest/AppData/Local/Erlang/My App/Cache"
4> filename:basedir(user_cache, "My App", #{version=>"1.2"}).
"c:/Users/otptest/AppData/Local/My App/1.2/Cache"
5> filename:basedir(user_cache, "My App", #{author=>"Erlang",version=>"1.2"}).
"c:/Users/otptest/AppData/Local/Erlang/My App/1.2/Cache"
  • user_config

The path location is intended for persistent configuration files.

  • On Linux: Respects the os environment variable XDG_CONFIG_HOME.
2> filename:basedir(user_config, "my_application", #{os=>linux}).
"/home/otptest/.config/my_application"
  • On Darwin:
2> filename:basedir(user_config, "my_application", #{os=>darwin}).
"/home/otptest/Library/Application Support/my_application"
  • On Windows:
1> filename:basedir(user_config, "My App").
"c:/Users/otptest/AppData/Roaming/My App"
2> filename:basedir(user_config, "My App", #{author=>"Erlang", version=>"1.2"}).
"c:/Users/otptest/AppData/Roaming/Erlang/My App/1.2"
  • user_data

The path location is intended for persistent data files.

  • On Linux: Respects the os environment variable XDG_DATA_HOME.
3> filename:basedir(user_data, "my_application", #{os=>linux}).
"/home/otptest/.local/my_application"
  • On Darwin:
3> filename:basedir(user_data, "my_application", #{os=>darwin}).
"/home/otptest/Library/Application Support/my_application"
  • On Windows:
8> filename:basedir(user_data, "My App").
"c:/Users/otptest/AppData/Local/My App"
9> filename:basedir(user_data, "My App",#{author=>"Erlang",version=>"1.2"}).
"c:/Users/otptest/AppData/Local/Erlang/My App/1.2"
  • user_log

The path location is intended for transient log files on a local machine.

  • On Linux: Respects the os environment variable XDG_CACHE_HOME.
4> filename:basedir(user_log, "my_application", #{os=>linux}).
"/home/otptest/.cache/my_application/log"
  • On Darwin:
4> filename:basedir(user_log, "my_application", #{os=>darwin}).
"/home/otptest/Library/Logs/my_application"
  • On Windows:
12> filename:basedir(user_log, "My App").
"c:/Users/otptest/AppData/Local/My App/Logs"
13> filename:basedir(user_log, "My App",#{author=>"Erlang",version=>"1.2"}).
"c:/Users/otptest/AppData/Local/Erlang/My App/1.2/Logs"
  • site_config
    • On Linux: Respects the os environment variable XDG_CONFIG_DIRS.
5> filename:basedir(site_config, "my_application", #{os=>linux}).
["/usr/local/share/my_application",
 "/usr/share/my_application"]
6> os:getenv("XDG_CONFIG_DIRS").
"/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg"
7> filename:basedir(site_config, "my_application", #{os=>linux}).
["/etc/xdg/xdg-ubuntu/my_application",
 "/usr/share/upstart/xdg/my_application",
 "/etc/xdg/my_application"]
8> os:unsetenv("XDG_CONFIG_DIRS").
true
9> filename:basedir(site_config, "my_application", #{os=>linux}).
["/etc/xdg/my_application"]
  • On Darwin:
5> filename:basedir(site_config, "my_application", #{os=>darwin}).
["/Library/Application Support/my_application"]
  • site_data
    • On Linux: Respects the os environment variable XDG_DATA_DIRS.

...and the vibe check continues πŸ’… because basedir/3 has opinions depending on which OS you're on, bestie, and we were literally mid-example:

10> os:getenv("XDG_DATA_DIRS").
"/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/"
11> filename:basedir(site_data, "my_application", #{os=>linux}).
["/usr/share/ubuntu/my_application",
 "/usr/share/gnome/my_application",
 "/usr/local/share/my_application",
 "/usr/share/my_application"]
12> os:unsetenv("XDG_DATA_DIRS").
true
13> filename:basedir(site_data, "my_application", #{os=>linux}).
["/usr/local/share/my_application",
 "/usr/share/my_application"]

On Darwin:

5> filename:basedir(site_data, "my_application", #{os=>darwin}).
["/Library/Application Support/my_application"]

🌸 basename(Filename) -> file:filename_all()

when Filename :: file:name_all().

okay so this one hands you back the last component of Filename β€” or, if there's not a single directory separator in there, it just gives you Filename right back. no notes, iconic behavior. ✨

Examples:

5> filename:basename("foo").
"foo"
6> filename:basename("/usr/foo").
"foo"
7> filename:basename("/").
[]

πŸŽ€ basename(Filename, Ext) -> file:filename_all()

when
    Filename :: file:name_all(),
    Ext :: file:name_all().

Returns the last component of Filename with extension Ext stripped. πŸ’…

Use this one when you want to yeet a (possible) specific extension. And listen β€” if you don't even know which extension is sitting there and you just want it gone, use rootname(basename(Filename)) instead. that's the move. fr fr.

Examples:

8> filename:basename("~/src/kalle.erl", ".erl").
"kalle"
9> filename:basename("~/src/kalle.beam", ".erl").
"kalle.beam"
10> filename:basename("~/src/kalle.old.erl", ".erl").
"kalle.old"
11> filename:rootname(filename:basename("~/src/kalle.erl")).
"kalle"
12> filename:rootname(filename:basename("~/src/kalle.beam")).
"kalle"

πŸ¦‹ dirname(Filename) -> file:filename_all()

when Filename :: file:name_all().

Returns the directory part of Filename. like, the folder part. the parent. iykyk. 🌈

Examples:

13> filename:dirname("/usr/src/kalle.erl").
"/usr/src"
14> filename:dirname("kalle.erl").
"."

5> filename:dirname("\\usr\\src/kalle.erl"). % Windows
"/usr/src"

✨ extension(Filename) -> file:filename_all()

when Filename :: file:name_all().

Returns the file extension of Filename, including the period. If there's no extension, you get an empty string. that's it, that's the function. πŸ“

Examples:

15> filename:extension("foo.erl").
".erl"
16> filename:extension("bork.src/kalle").
[]

🧚 flatten(Filename) -> file:filename_all()

when Filename :: file:name_all().

Converts a possibly deep list filename made out of characters and atoms into the matching flat string filename. so it takes your little nested list situation and flattens it out into one chill string. obsessed. πŸ’œ

🌸 join(Components) -> file:filename_all()

when Components :: [file:name_all()].

Joins a list of filename Components together with directory separators. And here's the plot twist: if one of the elements of Components has an absolute path in it (like "/xxx"), then all the elements before it, if there are any, get dropped from the result. gone. not invited. 😭

The result comes back "normalized":

  • Redundant directory separators are removed.
  • On Windows, all directory separators are forward slashes and the drive letter is in lower case.

Examples:

17> filename:join(["/usr", "local", "bin"]).
"/usr/local/bin"
18> filename:join(["a/b///c/"]).
"a/b/c"

6> filename:join(["B:a\\b///c/"]). % Windows
"b:a/b/c"

πŸŽ€ join(Name1, Name2) -> file:filename_all()

when Name1 :: file:name_all(), Name2 :: file:name_all().

Joins two filename components with directory separators. This is literally the same thing as join([Name1, Name2]). same vibe, shorter syntax, slay. πŸ’…

πŸ’– nativename(Path) -> file:filename_all()

when Path :: file:name_all().

Converts Path into a form that the command shell and native applications on the current platform will accept. On Windows, forward slashes become backward slashes. And on all platforms the name gets normalized exactly like join/1 does it. ✨

Examples:

19> filename:nativename("/usr/local/bin/"). % Unix
"/usr/local/bin"

7> filename:nativename("/usr/local/bin/"). % Windows
"\\usr\\local\\bin"

🌈 pathtype(Path) -> absolute | relative | volumerelative

when Path :: file:name_all().

Returns the path type, which is one of these three besties:

  • absolute β€” the path name refers to a specific file on a specific volume.
    • Unix example: /usr/local/bin
    • Windows example: D:/usr/local/bin
  • relative β€” the path name is relative to the current working directory on the current volume.
    • Example: foo/bar, ../src
  • volumerelative β€” the path name is relative to the current working directory on a specified volume, or it's a specific file on the current working volume.
    • Windows example: D:bar.erl, /bar/foo.erl

🫢 rootname(Filename) -> file:filename_all()

when Filename :: file:name_all().

Removes the filename extension. bye bye .erl bestie πŸ‘‹

Examples:

1> filename:rootname("/bork.src/kalle").
"/bork.src/kalle"
2> filename:rootname("/bork.src/foo.erl").
"/bork.src/foo"

⭐ rootname(Filename, Ext) -> file:filename_all()

when
    Filename :: file:name_all(),
    Ext :: file:name_all().

Removes the filename extension Ext from Filename. only that specific one tho β€” it's not out here guessing.

Examples:

1> filename:rootname("/bork.src/foo.erl", ".erl").
"/bork.src/foo"
2> filename:rootname("/bork.src/foo.beam", ".erl").
"/bork.src/foo.beam"

πŸ¦‹ split(Filename) -> Components

when
    Filename :: file:name_all(),
    Components :: [file:name_all()].

Returns a list where the elements are the path components of Filename. it's join/1's opposite number and honestly they're giving enemies to lovers. πŸ’€

Examples:

24> filename:split("/usr/local/bin").
["/","usr","local","bin"]
25> filename:split("foo/bar").
["foo","bar"]
26> filename:split("a:\\msdev\\include").
["a:/","msdev","include"]

and that's the whole page, bestie!! πŸŽ‰ you now know every single one of these functions and no one can take that from you. this slay of a manual page comes to you from Ericsson AB, running stdlib 8.0.4, filed under filename(3). go forth and manipulate paths responsibly, queen πŸ‘‘πŸ’–

πŸ“¦ where this page comes from