29 Input/output library [input.output]

29.11 File systems [filesystems]

29.11.7 Class path [fs.class.path]

29.11.7.4 Members [fs.path.member]

29.11.7.4.1 Constructors [fs.path.construct]

path() noexcept;
Postconditions: empty() == true.
path(const path& p); path(path&& p) noexcept;
Effects: Constructs an object of class path having the same pathname in the native and generic formats, respectively, as the original value of p.
In the second form, p is left in a valid but unspecified state.
path(string_type&& source, format fmt = auto_format);
Effects: Constructs an object of class path for which the pathname in the detected-format of source has the original value of source ([fs.path.fmt.cvt]), converting format if required ([fs.path.fmt.cvt]).
source is left in a valid but unspecified state.
template<class Source> path(const Source& source, format fmt = auto_format); template<class InputIterator> path(InputIterator first, InputIterator last, format fmt = auto_format);
Effects: Let s be the effective range of source ([fs.path.req]) or the range [first, last), with the encoding converted if required ([fs.path.cvt]).
Finds the detected-format of s ([fs.path.fmt.cvt]) and constructs an object of class path for which the pathname in that format is s.
template<class Source> path(const Source& source, const locale& loc, format fmt = auto_format); template<class InputIterator> path(InputIterator first, InputIterator last, const locale& loc, format fmt = auto_format);
Mandates: The value type of Source and InputIterator is char.
Effects: Let s be the effective range of source or the range [first, last), after converting the encoding as follows:
  • If value_­type is wchar_­t, converts to the native wide encoding ([fs.path.type.cvt]) using the codecvt<wchar_­t, char, mbstate_­t> facet of loc.
  • Otherwise a conversion is performed using the codecvt<wchar_­t, char, mbstate_­t> facet of loc, and then a second conversion to the current ordinary encoding.
Finds the detected-format of s ([fs.path.fmt.cvt]) and constructs an object of class path for which the pathname in that format is s.
Example
:
A string is to be read from a database that is encoded in ISO/IEC 8859-1, and used to create a directory:
namespace fs = std::filesystem;
std::string latin1_string = read_latin1_data();
codecvt_8859_1<wchar_t> latin1_facet;
std::locale latin1_locale(std::locale(), latin1_facet);
fs::create_directory(fs::path(latin1_string, latin1_locale));
For POSIX-based operating systems, the path is constructed by first using latin1_­facet to convert ISO/IEC 8859-1 encoded latin1_­string to a wide character string in the native wide encoding ([fs.path.type.cvt]).
The resulting wide string is then converted to an ordinary character pathname string in the current native ordinary encoding.
If the native wide encoding is UTF-16 or UTF-32, and the current native ordinary encoding is UTF-8, all of the characters in the ISO/IEC 8859-1 character set will be converted to their Unicode representation, but for other native ordinary encodings some characters may have no representation.
For Windows-based operating systems, the path is constructed by using latin1_­facet to convert ISO/IEC 8859-1 encoded latin1_­string to a UTF-16 encoded wide character pathname string.
All of the characters in the ISO/IEC 8859-1 character set will be converted to their Unicode representation.
— end example
 ]

29.11.7.4.2 Assignments [fs.path.assign]

path& operator=(const path& p);
Effects: If *this and p are the same object, has no effect.
Otherwise, sets both respective pathnames of *this to the respective pathnames of p.
Returns: *this.
path& operator=(path&& p) noexcept;
Effects: If *this and p are the same object, has no effect.
Otherwise, sets both respective pathnames of *this to the respective pathnames of p.
p is left in a valid but unspecified state.
Note
:
A valid implementation is swap(p).
— end note
 ]
Returns: *this.
path& operator=(string_type&& source); path& assign(string_type&& source);
Effects: Sets the pathname in the detected-format of source to the original value of source.
source is left in a valid but unspecified state.
Returns: *this.
template<class Source> path& operator=(const Source& source); template<class Source> path& assign(const Source& source); template<class InputIterator> path& assign(InputIterator first, InputIterator last);
Effects: Let s be the effective range of source ([fs.path.req]) or the range [first, last), with the encoding converted if required ([fs.path.cvt]).
Finds the detected-format of s ([fs.path.fmt.cvt]) and sets the pathname in that format to s.
Returns: *this.

29.11.7.4.3 Appends [fs.path.append]

The append operations use operator/= to denote their semantic effect of appending preferred-separator when needed.
path& operator/=(const path& p);
Effects: If p.is_­absolute() || (p.has_­root_­name() && p.root_­name() != root_­name()), then operator=(p).
Otherwise, modifies *this as if by these steps:
  • If p.has_­root_­directory(), then removes any root directory and relative path from the generic format pathname. Otherwise, if !has_­root_­directory() && is_­absolute() is true or if has_­filename() is true, then appends path​::​preferred_­separator to the generic format pathname.
  • Then appends the native format pathname of p, omitting any root-name from its generic format pathname, to the native format pathname.
Example
:
Even if //host is interpreted as a root-name, both of the paths path("//host")/"foo" and path("//host/")/"foo" equal "//host/foo" (although the former might use backslash as the preferred separator).
Expression examples:
// On POSIX,
path("foo") /= path("");        // yields path("foo/")
path("foo") /= path("/bar");    // yields path("/bar")

// On Windows,
path("foo") /= path("");        // yields path("foo\\")
path("foo") /= path("/bar");    // yields path("/bar")
path("foo") /= path("c:/bar");  // yields path("c:/bar")
path("foo") /= path("c:");      // yields path("c:")
path("c:") /= path("");         // yields path("c:")
path("c:foo") /= path("/bar");  // yields path("c:/bar")
path("c:foo") /= path("c:bar"); // yields path("c:foo\\bar")
— end example
 ]
Returns: *this.
template<class Source> path& operator/=(const Source& source); template<class Source> path& append(const Source& source);
Effects: Equivalent to: return operator/=(path(source));
template<class InputIterator> path& append(InputIterator first, InputIterator last);
Effects: Equivalent to: return operator/=(path(first, last));

29.11.7.4.4 Concatenation [fs.path.concat]

path& operator+=(const path& x); path& operator+=(const string_type& x); path& operator+=(basic_string_view<value_type> x); path& operator+=(const value_type* x); template<class Source> path& operator+=(const Source& x); template<class Source> path& concat(const Source& x);
Effects: Appends path(x).native() to the pathname in the native format.
Note
:
This directly manipulates the value of native() and may not be portable between operating systems.
— end note
 ]
Returns: *this.
path& operator+=(value_type x); template<class EcharT> path& operator+=(EcharT x);
Effects: Equivalent to: return *this += basic_­string_­view(&x, 1);
template<class InputIterator> path& concat(InputIterator first, InputIterator last);
Effects: Equivalent to: return *this += path(first, last);

29.11.7.4.5 Modifiers [fs.path.modifiers]

void clear() noexcept;
Postconditions: empty() == true.
path& make_preferred();
Effects: Each directory-separator of the pathname in the generic format is converted to preferred-separator.
Returns: *this.
Example
:
path p("foo/bar");
std::cout << p << '\n';
p.make_preferred();
std::cout << p << '\n';
On an operating system where preferred-separator is a slash, the output is:
"foo/bar"
"foo/bar"
On an operating system where preferred-separator is a backslash, the output is:
"foo/bar"
"foo\bar"
— end example
 ]
path& remove_filename();
Effects: Remove the generic format pathname of filename() from the generic format pathname.
Postconditions: !has_­filename().
Returns: *this.
Example
:
path("foo/bar").remove_filename();      // yields "foo/"
path("foo/").remove_filename();         // yields "foo/"
path("/foo").remove_filename();         // yields "/"
path("/").remove_filename();            // yields "/"
— end example
 ]
path& replace_filename(const path& replacement);
Effects: Equivalent to:
remove_filename();
operator/=(replacement);
Returns: *this.
Example
:
path("/foo").replace_filename("bar");   // yields "/bar" on POSIX
path("/").replace_filename("bar");      // yields "/bar" on POSIX
— end example
 ]
path& replace_extension(const path& replacement = path());
Effects:
  • Any existing extension() ([fs.path.decompose]) is removed from the pathname in the generic format, then
  • If replacement is not empty and does not begin with a dot character, a dot character is appended to the pathname in the generic format, then
  • operator+=(replacement);.
Returns: *this.
void swap(path& rhs) noexcept;
Effects: Swaps the contents (in all formats) of the two paths.
Complexity: Constant time.

29.11.7.4.6 Native format observers [fs.path.native.obs]

The string returned by all native format observers is in the native pathname format ([fs.class.path]).
const string_type& native() const noexcept;
Returns: The pathname in the native format.
const value_type* c_str() const noexcept;
Effects: Equivalent to: return native().c_­str();
operator string_type() const;
Returns: native().
Note
:
Conversion to string_­type is provided so that an object of class path can be given as an argument to existing standard library file stream constructors and open functions.
— end note
 ]
template<class EcharT, class traits = char_traits<EcharT>, class Allocator = allocator<EcharT>> basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const;
Returns: native().
Remarks: All memory allocation, including for the return value, shall be performed by a.
Conversion, if any, is specified by [fs.path.cvt].
std::string string() const; std::wstring wstring() const; std::u8string u8string() const; std::u16string u16string() const; std::u32string u32string() const;
Returns: native().
Remarks: Conversion, if any, is performed as specified by [fs.path.cvt].

29.11.7.4.7 Generic format observers [fs.path.generic.obs]

Generic format observer functions return strings formatted according to the generic pathname format.
A single slash ('/') character is used as the directory-separator.
Example
:
On an operating system that uses backslash as its preferred-separator,
path("foo\\bar").generic_string()
returns "foo/bar".
— end example
 ]
template<class EcharT, class traits = char_traits<EcharT>, class Allocator = allocator<EcharT>> basic_string<EcharT, traits, Allocator> generic_string(const Allocator& a = Allocator()) const;
Returns: The pathname in the generic format.
Remarks: All memory allocation, including for the return value, shall be performed by a.
Conversion, if any, is specified by [fs.path.cvt].
std::string generic_string() const; std::wstring generic_wstring() const; std::u8string generic_u8string() const; std::u16string generic_u16string() const; std::u32string generic_u32string() const;
Returns: The pathname in the generic format.
Remarks: Conversion, if any, is specified by [fs.path.cvt].

29.11.7.4.8 Compare [fs.path.compare]

int compare(const path& p) const noexcept;
Returns:
  • Let rootNameComparison be the result of this->root_­name().native().compare(p.root_­name().native()). If rootNameComparison is not 0, rootNameComparison.
  • Otherwise, if !this->has_­root_­directory() and p.has_­root_­directory(), a value less than 0.
  • Otherwise, if this->has_­root_­directory() and !p.has_­root_­directory(), a value greater than 0.
  • Otherwise, if native() for the elements of this->relative_­path() are lexicographically less than native() for the elements of p.relative_­path(), a value less than 0.
  • Otherwise, if native() for the elements of this->relative_­path() are lexicographically greater than native() for the elements of p.relative_­path(), a value greater than 0.
  • Otherwise, 0.
int compare(const string_type& s) const; int compare(basic_string_view<value_type> s) const; int compare(const value_type* s) const;
Effects: Equivalent to: return compare(path(s));

29.11.7.4.9 Decomposition [fs.path.decompose]

path root_name() const;
Returns: root-name, if the pathname in the generic format includes root-name, otherwise path().
path root_directory() const;
Returns: root-directory, if the pathname in the generic format includes root-directory, otherwise path().
path root_path() const;
Returns: root_­name() / root_­directory().
path relative_path() const;
Returns: A path composed from the pathname in the generic format, if empty() is false, beginning with the first filename after root_­path().
Otherwise, path().
path parent_path() const;
Returns: *this if has_­relative_­path() is false, otherwise a path whose generic format pathname is the longest prefix of the generic format pathname of *this that produces one fewer element in its iteration.
path filename() const;
Returns: relative_­path().empty() ? path() : *--end().
Example
:
path("/foo/bar.txt").filename();        // yields "bar.txt"
path("/foo/bar").filename();            // yields "bar"
path("/foo/bar/").filename();           // yields ""
path("/").filename();                   // yields ""
path("//host").filename();              // yields ""
path(".").filename();                   // yields "."
path("..").filename();                  // yields ".."
— end example
 ]
path stem() const;
Returns: Let f be the generic format pathname of filename().
Returns a path whose pathname in the generic format is
  • f, if it contains no periods other than a leading period or consists solely of one or two periods;
  • otherwise, the prefix of f ending before its last period.
Example
:
std::cout << path("/foo/bar.txt").stem();       // outputs "bar"
path p = "foo.bar.baz.tar";
for (; !p.extension().empty(); p = p.stem())
  std::cout << p.extension() << '\n';
  // outputs: .tar
  //          .baz
  //          .bar
— end example
 ]
path extension() const;
Returns: A path whose pathname in the generic format is the suffix of filename() not included in stem().
Example
:
path("/foo/bar.txt").extension();       // yields ".txt" and stem() is "bar"
path("/foo/bar").extension();           // yields "" and stem() is "bar"
path("/foo/.profile").extension();      // yields "" and stem() is ".profile"
path(".bar").extension();               // yields "" and stem() is ".bar"
path("..bar").extension();              // yields ".bar" and stem() is "."
— end example
 ]
Note
:
The period is included in the return value so that it is possible to distinguish between no extension and an empty extension.
— end note
 ]
Note
:
On non-POSIX operating systems, for a path p, it may not be the case that p.stem() + p.extension() == p.filename(), even though the generic format pathnames are the same.
— end note
 ]

29.11.7.4.10 Query [fs.path.query]

[[nodiscard]] bool empty() const noexcept;
Returns: true if the pathname in the generic format is empty, otherwise false.
bool has_root_path() const;
Returns: !root_­path().empty().
bool has_root_name() const;
Returns: !root_­name().empty().
bool has_root_directory() const;
Returns: !root_­directory().empty().
bool has_relative_path() const;
Returns: !relative_­path().empty().
bool has_parent_path() const;
Returns: !parent_­path().empty().
bool has_filename() const;
Returns: !filename().empty().
bool has_stem() const;
Returns: !stem().empty().
bool has_extension() const;
Returns: !extension().empty().
bool is_absolute() const;
Returns: true if the pathname in the native format contains an absolute path ([fs.class.path]), otherwise false.
Example
:
path("/").is_­absolute() is true for POSIX-based operating systems, and false for Windows-based operating systems.
— end example
 ]
bool is_relative() const;
Returns: !is_­absolute().

29.11.7.4.11 Generation [fs.path.gen]

path lexically_normal() const;
Returns: A path whose pathname in the generic format is the normal form ([fs.path.generic]) of the pathname in the generic format of *this.
Example
:
assert(path("foo/./bar/..").lexically_normal() == "foo/");
assert(path("foo/.///bar/../").lexically_normal() == "foo/");
The above assertions will succeed.
On Windows, the returned path's directory-separator characters will be backslashes rather than slashes, but that does not affect path equality.
— end example
 ]
path lexically_relative(const path& base) const;
Returns: *this made relative to base.
Does not resolve ([fs.class.path]) symlinks.
Does not first normalize ([fs.path.generic]) *this or base.
Effects: If:
  • root_­name() != base.root_­name() is true, or
  • is_­absolute() != base.is_­absolute() is true, or
  • !has_­root_­directory() && base.has_­root_­directory() is true, or
  • any filename in relative_­path() or base.relative_­path() can be interpreted as a root-name,
returns path().
Note
:
On a POSIX implementation, no filename in a relative-path is acceptable as a root-name.
— end note
 ]
Determines the first mismatched element of *this and base as if by:
auto [a, b] = mismatch(begin(), end(), base.begin(), base.end());
Then,
  • if a == end() and b == base.end(), returns path("."); otherwise
  • let n be the number of filename elements in [b, base.end()) that are not dot or dot-dot or empty, minus the number that are dot-dot. If n<0, returns path(); otherwise
  • if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
  • returns an object of class path that is default-constructed, followed by
    • application of operator/=(path("..")) n times, and then
    • application of operator/= for each element in [a, end()).
Example
:
assert(path("/a/d").lexically_relative("/a/b/c") == "../../d");
assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c");
assert(path("a/b/c").lexically_relative("a") == "b/c");
assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
assert(path("a/b/c").lexically_relative("a/b/c") == ".");
assert(path("a/b").lexically_relative("c/d") == "../../a/b");
The above assertions will succeed.
On Windows, the returned path's directory-separator characters will be backslashes rather than slashes, but that does not affect path equality.
— end example
 ]
Note
:
If symlink following semantics are desired, use the operational function relative().
— end note
 ]
Note
:
If normalization ([fs.path.generic]) is needed to ensure consistent matching of elements, apply lexically_­normal() to *this, base, or both.
— end note
 ]
path lexically_proximate(const path& base) const;
Returns: If the value of lexically_­relative(base) is not an empty path, return it.
Otherwise return *this.
Note
:
If symlink following semantics are desired, use the operational function proximate().
— end note
 ]
Note
:
If normalization ([fs.path.generic]) is needed to ensure consistent matching of elements, apply lexically_­normal() to *this, base, or both.
— end note
 ]