• 9.3. 文件与目录

    9.3. 文件与目录

    boost::filesystem::path 的各个方法内部其实只是对字符串进行处理。 它们可以用来访问一个路径的各个组件、相互添加路径等等。

    为了处理硬盘上的物理文件和目录,提供了几个独立的函数。 这些函数需要一个或多个 boost::filesystem::path 类型的参数,并且在其内部会调用操作系统功能来处理这些文件或目录。

    在介绍各个函数之前,很重要的一点是要弄明白出现错误时会发生什么。 所有要在内部访问操作系统功能的函数都有可能失败。 在失败的情况下,将抛出一个类型为 boost::filesystem::filesystem_error 的异常。 这个类是派生自 boost::system::system_error 的,因此适用于 Boost.System 框架。

    除了继承自父类 boost::system::system_errorwhat()code() 方法以外,还有另外两个方法:path1()path2()。 它们均返回一个类型为 boost::filesystem::path 的对象,因此在发生错误时可以很容易地确定路径信息 - 即使是对那些需要两个 boost::filesystem::path 参数的函数。

    多数函数存在两个变体:在失败时,一个会抛出类型为 boost::filesystem::filesystem_error 的异常,而另一个则返回类型为 boost::system::error_code 的对象。 对于后者,需要对返回值进行明确的检查以确定是否出错。

    以下例子介绍了一个函数,它可以查询一个文件或目录的状态。

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. boost::filesystem::path p("C:\\");
    7. try
    8. {
    9. boost::filesystem::file_status s = boost::filesystem::status(p);
    10. std::cout << boost::filesystem::is_directory(s) << std::endl;
    11. }
    12. catch (boost::filesystem::filesystem_error &e)
    13. {
    14. std::cerr << e.what() << std::endl;
    15. }
    16. }
    • 下载源代码

    boost::filesystem::status() 返回一个 boost::filesystem::file_status 类型的对象,该对象可以被传递给其它辅助函数来评估。 例如,如果查询的是一个目录的状态,则 boost::filesystem::is_directory() 将返回 true。 除了 boost::filesystem::is_directory(),还有其它函数,如 boost::filesystem::is_regular_file(), boost::filesystem::is_symlink()boost::filesystem::exists(),它们都会返回一个 bool 类型的值。

    除了 boost::filesystem::status(),另一个名为 boost::filesystem::symlink_status() 的函数可用于查询一个符号链接的状态。 在此情况下,实际上查询的是符号链接所指向的文件的状态。在 Windows 中,符号链接以 lnk 文件扩展名识别。

    另有一组函数可用于查询文件和目录的属性。

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. boost::filesystem::path p("C:\\Windows\\win.ini");
    7. try
    8. {
    9. std::cout << boost::filesystem::file_size(p) << std::endl;
    10. }
    11. catch (boost::filesystem::filesystem_error &e)
    12. {
    13. std::cerr << e.what() << std::endl;
    14. }
    15. }
    • 下载源代码

    函数 boost::filesystem::file_size() 以字节数返回一个文件的大小。

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3. #include <ctime>
    4.  
    5. int main()
    6. {
    7. boost::filesystem::path p("C:\\Windows\\win.ini");
    8. try
    9. {
    10. std::time_t t = boost::filesystem::last_write_time(p);
    11. std::cout << std::ctime(&t) << std::endl;
    12. }
    13. catch (boost::filesystem::filesystem_error &e)
    14. {
    15. std::cerr << e.what() << std::endl;
    16. }
    17. }
    • 下载源代码

    要获得一个文件最后被修改的时间,可使用 boost::filesystem::last_write_time()

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. boost::filesystem::path p("C:\\");
    7. try
    8. {
    9. boost::filesystem::space_info s = boost::filesystem::space(p);
    10. std::cout << s.capacity << std::endl;
    11. std::cout << s.free << std::endl;
    12. std::cout << s.available << std::endl;
    13. }
    14. catch (boost::filesystem::filesystem_error &e)
    15. {
    16. std::cerr << e.what() << std::endl;
    17. }
    18. }
    • 下载源代码

    boost::filesystem::space() 用于取回磁盘的总空间和剩余空间。 它返回一个 boost::filesystem::spaceinfo 类型的对象,其中定义了三个公有属性:_capacity, freeavailable。 这三个属性的类型均为 boost::uintmax_t,该类型定义于 Boost.Integer 库,通常是 unsigned long long 的 typedef。 磁盘空间是以字节数来计算的。

    目前所看到的函数都不会触及文件和目录本身,不过有另外几个函数可以用于创建、改名或删除文件和目录。

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. boost::filesystem::path p("C:\\Test");
    7. try
    8. {
    9. if (boost::filesystem::create_directory(p))
    10. {
    11. boost::filesystem::rename(p, "C:\\Test2");
    12. boost::filesystem::remove("C:\\Test2");
    13. }
    14. }
    15. catch (boost::filesystem::filesystem_error &e)
    16. {
    17. std::cerr << e.what() << std::endl;
    18. }
    19. }
    • 下载源代码

    以上例子应该是自解释的。 仔细察看,可以看到传递给各个函数的不一定是 boost::filesystem::path 类型的对象,也可以是一个简单的字符串。 这是可以的,因为 boost::filesystem::path 提供了一个非显式的构造函数,可以从简单的字符串转换为 boost::filesystem::path 类型的对象。 这实际上简化了 Boost.Filesystem 的使用,因为可以无须显式创建一个对象。

    还有其它的函数,如 create_symlink() 用于创建符号链接,以及 copy_file() 用于复制文件或目录。

    以下例子中介绍了一个函数,基于一个文件名或一小节路径来创建一个绝对路径。

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. try
    7. {
    8. std::cout << boost::filesystem::complete("photo.jpg") << std::endl;
    9. }
    10. catch (boost::filesystem::filesystem_error &e)
    11. {
    12. std::cerr << e.what() << std::endl;
    13. }
    14. }
    • 下载源代码

    输出哪个路径是由该程序运行时所处的路径决定的。 例如,如果该例子从 C:\ 运行,输出将是 C:/photo.jpg

    请再次留意斜杠符 /! 如果想得到一个平台相关的路径,则需要初始化一个 boost::filesystem::path 类型的对象,且必须调用 file_string()

    要取出一个相对于其它目录的绝对路径,可将第二个参数传递给 boost::filesystem::complete()

    1. #include <boost/filesystem.hpp>
    2. #include <iostream>
    3.  
    4. int main()
    5. {
    6. try
    7. {
    8. std::cout << boost::filesystem::complete("photo.jpg", "D:\\") << std::endl;
    9. }
    10. catch (boost::filesystem::filesystem_error &e)
    11. {
    12. std::cerr << e.what() << std::endl;
    13. }
    14. }
    • 下载源代码

    现在,该程序显示的是 D:/photo.jpg

    最后,还有一个辅助函数用于取出当前工作目录,如下例所示。

    1. #include <windows.h>
    2. #include <boost/filesystem.hpp>
    3. #include <iostream>
    4.  
    5. int main()
    6. {
    7. try
    8. {
    9. std::cout << boost::filesystem::current_path() << std::endl;
    10. SetCurrentDirectory("C:\\");
    11. std::cout << boost::filesystem::current_path() << std::endl;
    12. }
    13. catch (boost::filesystem::filesystem_error &e)
    14. {
    15. std::cerr << e.what() << std::endl;
    16. }
    17. }
    • 下载源代码

    以上程序只能在 Windows 中执行,这是 SetCurrentDirectory() 函数的原因。 这个函数更换了当前工作目录,因此对 boost::filesystem::current_path() 的两次调用将返回不同的结果。

    函数 boost::filesystem::initial_path() 用于返回应用程序开始执行时所处的目录。 但是,这个函数取决于操作系统的支持,因此如果需要可移植性,建议不要使用。 在这种情况下,Boost.Filesystem 文档中建议的方法是,可以在程序开始时保存 boost::filesystem::current_path() 的返回值,以备后用。