使用相对路径获取规范的文件路径

上一节中,我们对路径进行了标准化输出。使用了filesystem::path类,并且了解了如何获取路径,并进行检查,以及其他一些原理性的东西。也能帮助我们将字符串组成路径,从而对路径进行再次解析。

path已经将操作系统的一些细节为我们进行了封装,不过我们还是需要了解一些细节。

本节我们也将了解到,如何将绝对路径和相对路径进行合并和分解。

How to do it…

本节中,我们将围绕着相对路径和绝对路径进行,从而了解path类的有时,以及其对应的辅助函数。

  1. 包含必要的头文件,并声明所使用的命名空间:

    1. #include <iostream>
    2. #include <filesystem>
    3. using namespace std;
    4. using namespace filesystem;
  2. 然后,我们实例化一个path对象。不过这次,路径中的文件是否存在就没有那么重要了。这里有些函数,在文件不存在的时候会抛出异常。

    1. int main()
    2. {
    3. path p {"testdir/foobar.txt"};
  3. 现在我们来了解一下不同的文件系统库函数。current_path将返回我们执行程序的路径,也就是工作目录。absolute能接受一个相对地址,就像我们定义的p一样。system_complete在Linux,MacOS和类UNIX操作系统上与absolute的功能相同。在Windows下我们将获取一个带有盘符(比如c:)的绝对地址。canonicalabsolute的功能相同,不过其删除了所有的...。我们可以使用如下的方式使用这些函数:

    1. cout << "current_path : " << current_path()
    2. << "\nabsolute_path : " << absolute(p)
    3. << "\nsystem_complete : " << system_complete(p)
    4. << "\ncanonical(p) : " << canonical(p)
    5. << '\n';
  4. path另一个优势在于,其对/操作符进行了重载。通过这种方式我们可以连接文件夹和文件。让我们组合一个,然后进行打印:

    1. cout << path{"testdir"} / "foobar.txt" << '\n';
  5. 我们将canonical与合并的路径一起使用。通过给定canonical一个相对地址,比如"foobar.txt",和一个合并的绝对地址current_path() / "testdir",其将会返回给我们一个绝对地址。在另一个调用中,我们给定我么的路径为p(假设为"testdir/foobar.txt"),并且通过current_path()获取当前位置的绝对路径,我们这里就使用"testdir"好了。其结果与current_path()相同,因为间接获得了绝对地址。在这两次调用中,canonical将会返回给我们相同的绝对地址:

    1. cout << "canonical testdir : "
    2. << canonical("foobar.txt",
    3. current_path() / "testdir")
    4. << "\ncanonical testdir 2 : "
    5. << canonical(p, current_path() / "testdir/..")
    6. << '\n';
  6. 我们也可以对两个非标准化的路径进行比较。equivalence能接受两个路径,并在内部将两个路径进行标准化,如果这两个路径相同,就会返回true,否则会返回false。这个例子中,相应的路径必须存在,否则就会抛出一个异常:

    1. cout << "equivalence: "
    2. << equivalent("testdir/foobar.txt",
    3. "testdir/../testdir/foobar.txt")
    4. << '\n';
    5. }
  7. 编译并运行代码,将会得到如下的输出。current_path()会返回我笔记本上的HOME目录,因为我在这个路径下执行的程序。相对路径p会通过 absolute_pathsystem_completecanonical预先进行准备。我们能看到absolute_pathsystem_complete的结果都一样,因为我使用的是Mac系统。在使用Windows操作系统的机器上,system_complete将会前置一个C:,或者是工作路径的磁盘盘符:

    1. $ ./canonical_filepath
    2. current_path: "/Users/tfc"
    3. absolute_path : "/Users/tfc/testdir/foobar.txt"
    4. system_complete : "/Users/tfc/testdir/foobar.txt"
    5. canonical(p): "/Users/tfc/testdir/foobar.txt"
    6. "testdir/foobar.txt"
    7. canonical testdir : "/Users/tfc/testdir/foobar.txt"
    8. canonical testdir 2 : "/Users/tfc/testdir/foobar.txt"
    9. equivalence: 1
  8. 这个简单的程序中,就不对异常进行处理了。当从testdir文件夹中将foobar.txt文件删除时,程序将因为抛出异常的原因而终止。canonical函数需要路径真实存在。还有一个weakly_canonical,但其不符合我们的要求。

    1. $ ./canonial_filepath
    2. current_path: "/Users/tfc"
    3. absolute_path : "/Users/tfc/testdir/foobar.txt"
    4. system_complete : "/Users/tfc/testdir/foobar.txt"
    5. terminate called after throwing an instance of
    6. 'std::filesystem::v1::__cxx11::filesystem_error'
    7. what():filesystem error: cannot canonicalize:
    8. No such file or directory [testdir/foobar.txt] [/Users/tfc]

How it works…

本节的目的就是如何快速的组成新的路径。其主要还有通过path类重载的/操作符来完成。另外,文件系统函数的相对路径和绝对路径是一致的,并且路径中包含...

很多函数会返回一个转换或未转换的path实例。我们不会将所有函数都列在这里,如果想要了解它们,去看下C++手册是个不错的选择。

path类中有很多的成员函数,很值得一看。让我们来了解一下,对于一个路径来说,成员函数返回的是哪一部分。下面的图就为我们描述了在Windows和UNIX/Linux下,对应函数所返回的路径:

使用相对路径获取规范的文件路径 - 图1

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