使用相对路径获取规范的文件路径
上一节中,我们对路径进行了标准化输出。使用了filesystem::path类,并且了解了如何获取路径,并进行检查,以及其他一些原理性的东西。也能帮助我们将字符串组成路径,从而对路径进行再次解析。
path已经将操作系统的一些细节为我们进行了封装,不过我们还是需要了解一些细节。
本节我们也将了解到,如何将绝对路径和相对路径进行合并和分解。
How to do it...
本节中,我们将围绕着相对路径和绝对路径进行,从而了解path类的有时,以及其对应的辅助函数。
包含必要的头文件,并声明所使用的命名空间:
#include <iostream> #include <filesystem> using namespace std; using namespace filesystem;然后,我们实例化一个
path对象。不过这次,路径中的文件是否存在就没有那么重要了。这里有些函数,在文件不存在的时候会抛出异常。int main() { path p {"testdir/foobar.txt"};现在我们来了解一下不同的文件系统库函数。
current_path将返回我们执行程序的路径,也就是工作目录。absolute能接受一个相对地址,就像我们定义的p一样。system_complete在Linux,MacOS和类UNIX操作系统上与absolute的功能相同。在Windows下我们将获取一个带有盘符(比如c:)的绝对地址。canonical与absolute的功能相同,不过其删除了所有的.和..。我们可以使用如下的方式使用这些函数:cout << "current_path : " << current_path() << "\nabsolute_path : " << absolute(p) << "\nsystem_complete : " << system_complete(p) << "\ncanonical(p) : " << canonical(p) << '\n';path另一个优势在于,其对/操作符进行了重载。通过这种方式我们可以连接文件夹和文件。让我们组合一个,然后进行打印:cout << path{"testdir"} / "foobar.txt" << '\n';我们将
canonical与合并的路径一起使用。通过给定canonical一个相对地址,比如"foobar.txt",和一个合并的绝对地址current_path() / "testdir",其将会返回给我们一个绝对地址。在另一个调用中,我们给定我么的路径为p(假设为"testdir/foobar.txt"),并且通过current_path()获取当前位置的绝对路径,我们这里就使用"testdir"好了。其结果与current_path()相同,因为间接获得了绝对地址。在这两次调用中,canonical将会返回给我们相同的绝对地址:cout << "canonical testdir : " << canonical("foobar.txt", current_path() / "testdir") << "\ncanonical testdir 2 : " << canonical(p, current_path() / "testdir/..") << '\n';我们也可以对两个非标准化的路径进行比较。
equivalence能接受两个路径,并在内部将两个路径进行标准化,如果这两个路径相同,就会返回true,否则会返回false。这个例子中,相应的路径必须存在,否则就会抛出一个异常:cout << "equivalence: " << equivalent("testdir/foobar.txt", "testdir/../testdir/foobar.txt") << '\n'; }编译并运行代码,将会得到如下的输出。
current_path()会返回我笔记本上的HOME目录,因为我在这个路径下执行的程序。相对路径p会通过absolute_path,system_complete和canonical预先进行准备。我们能看到absolute_path和system_complete的结果都一样,因为我使用的是Mac系统。在使用Windows操作系统的机器上,system_complete将会前置一个C:,或者是工作路径的磁盘盘符:$ ./canonical_filepath current_path: "/Users/tfc" absolute_path : "/Users/tfc/testdir/foobar.txt" system_complete : "/Users/tfc/testdir/foobar.txt" canonical(p): "/Users/tfc/testdir/foobar.txt" "testdir/foobar.txt" canonical testdir : "/Users/tfc/testdir/foobar.txt" canonical testdir 2 : "/Users/tfc/testdir/foobar.txt" equivalence: 1这个简单的程序中,就不对异常进行处理了。当从
testdir文件夹中将foobar.txt文件删除时,程序将因为抛出异常的原因而终止。canonical函数需要路径真实存在。还有一个weakly_canonical,但其不符合我们的要求。$ ./canonial_filepath current_path: "/Users/tfc" absolute_path : "/Users/tfc/testdir/foobar.txt" system_complete : "/Users/tfc/testdir/foobar.txt" terminate called after throwing an instance of 'std::filesystem::v1::__cxx11::filesystem_error' what():filesystem error: cannot canonicalize: No such file or directory [testdir/foobar.txt] [/Users/tfc]
How it works...
本节的目的就是如何快速的组成新的路径。其主要还有通过path类重载的/操作符来完成。另外,文件系统函数的相对路径和绝对路径是一致的,并且路径中包含.和..。
很多函数会返回一个转换或未转换的path实例。我们不会将所有函数都列在这里,如果想要了解它们,去看下C++手册是个不错的选择。
path类中有很多的成员函数,很值得一看。让我们来了解一下,对于一个路径来说,成员函数返回的是哪一部分。下面的图就为我们描述了在Windows和UNIX/Linux下,对应函数所返回的路径:

这样我们就能很容易的了解到,path的那个函数返回的是绝对地址。相对地址中,root_path,root_name 和 root_directory部分都空的。relative_path将会返回一个相对地址。