File Paths in C++
The filesystem
library in C++17 provides functions to parse and construct file paths in a way that is portable between operating systems; dir/file
on Linux vs. dir\file
on Windows, for example.
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
int main() {
// path::preferred_separator should be used to construct paths in a
// portable way. We can use the / operator to concatenate path components.
fs::path p = "dir1" / "dir2" / "filename";
std::cout << "p: " << p << std::endl;
// You should always use the / operator instead of
// concatenating separators manually. In addition
// to providing portability, it will also
// normalize paths by removing superfluous separators
// and directory changes.
std::cout << "dir1//" / "filename" << std::endl;
std::cout << "dir1/../dir1" / "filename" << std::endl;
// parent_path() and filename() can be used to split a path to the
// directory and the file.
std::cout << "parent_path(p): " << p.parent_path() << std::endl;
std::cout << "filename(p): " << p.filename() << std::endl;
// We can check whether a path is absolute.
std::cout << fs::path("dir/file").is_absolute() << std::endl;
std::cout << fs::path("/dir/file").is_absolute() << std::endl;
std::string filename = "config.json";
// Some file names have extensions following a dot. We
// can get the extension of such names with extension().
std::cout << fs::path(filename).extension() << std::endl;
// To find the file's name with the extension removed,
// use stem().
std::cout << fs::path(filename).stem() << std::endl;
// lexically_relative() finds a relative path between a base and a
// target. It returns an empty path if the target cannot
// be made relative to base.
std::cout << fs::path("a/b/t/file").lexically_relative("a/b") << std::endl;
std::cout << fs::path("a/c/t/file").lexically_relative("a/b") << std::endl;
return 0;
}
To run the program, compile the code and use the resulting executable.
$ g++ -std=c++17 file_paths.cpp -o file_paths
$ ./file_paths
p: "dir1/dir2/filename"
"dir1/filename"
"dir1/filename"
parent_path(p): "dir1/dir2"
filename(p): "filename"
0
1
".json"
"config"
"t/file"
"../../c/t/file"
Note that the output might vary slightly depending on the operating system due to different path representations.
In C++, we use the filesystem
library which provides similar functionality to Go’s filepath
package. The fs::path
class is used to represent and manipulate file paths. The /
operator is overloaded to join path components, similar to filepath.Join
in Go.
Methods like parent_path()
, filename()
, is_absolute()
, extension()
, and stem()
correspond to Go’s Dir()
, Base()
, IsAbs()
, Ext()
, and the combination of Base()
and removing the extension.
The lexically_relative()
method in C++ is similar to Go’s Rel()
function, finding the relative path between two paths.
Remember to compile with C++17 or later to use the filesystem
library, and link against the appropriate library (you might need to add -lstdc++fs
to your compile command on some systems).