Boost Filesystem Library 路径 文件 目录

55 篇文章 3 订阅
34 篇文章 3 订阅

C++ 语言(实际上是 C++ 标准)的最常见问题之一是,缺乏定义良好的库来帮助处理文件系统查询和操作。由于这个原因,程序员不得不使用本机操作系统提供的应用程序编程接口(Application Program Interfaces,API),而这使得代码不能在平台之间移植。

Boost.Filesystem 库为对路径、文件和目录进行查询和操作提供了可移植的工具,已经被C++标准委员会接纳包含到TR2中。

头文件

#include <boost/filesystem.hpp>


所有Boost.Filesystem库的内容都处于名空间boost::filesystem之内。

认识basic_path类

在Boost.Filesystem库里basic_path是最重要的类,它以系统无关的方式保存路径、文件名。象std::basic_string 一样,针对char和wchar_t,分别特化了path和wpath。

basic_path的构造函数:

basic_path( const string_type & s ); 
basic_path( const value_type * s ); 
template <class InputIterator> basic_path(InputIterator s, InputIterator last);

输入参数是一个字符串(或字符迭代器),表示路径名,可以输入系统原生路径名或可移植路径名
原生路径名没啥好说的,比如C:/Windows; D:/abc/ttt.txt等
可移植路径名的定义和Unix的路径定义相同,以“/”作为路径分隔符。

basic_path成员函数:

成员函数作用
template <class InputIterator>basic_path& append(InputIterator first, InputIterator last);将字符串 s 或字符序列 [first,last) 中的路径元素追加到保存的路径中。
basic_path& remove_filename();去除路径中的文件名
basic_path& replace_extension( const string_type & new_extension = "" );替换扩展名
string_type string()得到可移植路径名
string_type file_string()得到系统原生文件名
string_type directory_string()得到系统原生路径名
string_type root_name() const;得到根名
string_type root_directory() const;得到根目录
basic_path root_path() const;得到根路径:根名+根目录
basic_path relative_path() const;得到相对路径
string_type filename() const;得到文件名
basic_path parent_path() const;得到父路径:根路径+相对路径
string_type stem(const Path & p) const;得到不带扩展名的文件名
string_type extension(const Path & p) const;得到扩展名
bool empty() const;path未赋值
bool is_complete() const;是否是完整路径
bool has_root_path() const;
bool has_root_name() const;
bool has_root_directory() const;
bool has_relative_path() const;
bool has_filename() const;
bool has_branch_path() const;
路经中是否包含指定的项

 

测试代码:
  1. #include "boost/filesystem.hpp"   // 包含所有需要的 Boost.Filesystem 声明
  2. #include <iostream>               // 使用 std::cout
  3. namespace fs = boost::filesystem;
  4. // 宏FSTEST:测试f的成员函数,输出成员函数名和结果
  5. #define FSTEST(x) std::cout << #x##": " << f.x << std::endl
  6. int main()
  7. {
  8.     fs::path f("//folder1//folder2//folder3//filename.ext");
  9.  
  10.     FSTEST(string());
  11.     FSTEST(file_string());
  12.     FSTEST(directory_string());
  13.     FSTEST(root_name());
  14.     FSTEST(root_directory());
  15.     FSTEST(root_path());
  16.     FSTEST(relative_path());
  17.     FSTEST(filename());
  18.     FSTEST(parent_path());
  19.     FSTEST(stem());
  20.     FSTEST(extension());
  21.  
  22.     FSTEST(replace_extension("new"));
  23.     char buf[]="hello";
  24.     FSTEST(append(buf, buf+sizeof(buf)));
  25.     FSTEST(remove_filename());
  26.  
  27.     return 0;
  28. }

 

输出:
string(): /folder1/folder2/folder3/filename.ext 
file_string(): /folder1/folder2/folder3/filename.ext 
directory_string(): /folder1/folder2/folder3/filename.ext 
root_name(): 
root_directory(): / 
root_path(): / 
relative_path(): folder1/folder2/folder3/filename.ext 
filename(): filename.ext 
parent_path(): /folder1/folder2/folder3 
stem(): filename 
extension(): .ext 
replace_extension("new"): /folder1/folder2/folder3/filename.new 
append(buf, buf+sizeof(buf)): /folder1/folder2/folder3/filename.new/hello 
remove_filename(): /folder1/folder2/folder3/filename.new/

 

常用函数

函数名作用
system_complete(path);返回完整路径(相对路径+当前路径)
exists(path);文件是否存在
is_directory(path);
is_directory(file_status);
是否是路径
is_regular_file(path);
is_regular_file(file_status);
是否是普通文件
is_symlink(path);
is_symlink(file_status);
是否是一个链接文件
file_status status(path);返回路径名对应的状态
template <class Path> const Path& initial_path();得到程序运行时的系统当前路径
template <class Path> Path current_path();得到系统当前路径
template <class Path> void current_path(const Path& p);改变当前路径
template <class Path> space_info space(const Path& p);得到指定路径下的空间信息,space_info 有capacity, free 和 available三个成员变量,分别表示容量,剩余空间和可用空间。
template <class Path> std::time_t last_write_time(const Path& p);最后修改时间
template <class Path> void last_write_time(const Path& p, const std::time_t new_time);修改最后修改时间
template <class Path> bool create_directory(const Path& dp);建立路径
template <class Path1, class Path2> void create_hard_link(const Path1& to_p, const Path2& from_p);
template <class Path1, class Path2> error_code create_hard_link(const Path1& to_p, 
const Path2& from_p, error_code& ec);
建立硬链接
template <class Path1, class Path2> void create_symlink(const Path1& to_p, const Path2& from_p);
template <class Path1, class Path2> error_code create_symlink(const Path1& to_p, const Path2& from_p, error_code& ec); 
建立软链接
template <class Path> void remove(const Path& p, system::error_code & ec = singular );删除文件
template <class Path> unsigned long remove_all(const Path& p);递归删除p中所有内容,返回删除文件的数量
template <class Path1, class Path2> void rename(const Path1& from_p, const Path2& to_p);重命名
template <class Path1, class Path2> void copy_file(const Path1& from_fp, const Path2& to_fp);拷贝文件
template <class Path> Path complete(const Path& p, const Path& base=initial_path<Path>());以base以基,p作为相对路径,返回其完整路径
template <class Path> bool create_directories(const Path & p);建立路径

 

路径迭代器

basic_directory_iterator

构造函数:

<code>explicit basic_directory_iterator(const Path& dp); 
basic_directory_iterator();</code>
basic_directory_iterator  从构造参数得到目录,每一次调用  operator++ ,它就查找并得到下一个文件名直到目录元素的末尾。不带参数的构造函数  basic_directory_iterator()  总是构造一个 end 迭代器对象,它是唯一一个用于结束条件的合法迭代器。

示例代码,得到指定目录下的所有文件名:

  1. void find_file( const fs::path & dir_path )
  2. {
  3.     if ( !fs::exists( dir_path ) ) return;
  4.     fs::directory_iterator end_itr; // 缺省构造生成一个结束迭代器
  5.     for ( fs::directory_iterator itr( dir_path );
  6.         itr != end_itr;
  7.         ++itr )
  8.     {
  9.         if ( fs::is_directory(itr->status()) )
  10.         {
  11.             find_file( itr->path() ); //递归查找
  12.         }
  13.         else
  14.         {
  15.             std::cout << *itr << std::endl;
  16.         }
  17.   }
  18. }

 

basic_recursive_directory_iterator

递归遍历目录的迭代器,它的构造参数与basic_directory_iterator相同,当调用 operator++时,如果当前值是一个目录,则进入下一级目录。
它有三个成员函数:

函数名作用
int level() const;得到当前搜索深度
void pop();调用pop()后,下一次递增就会直接返回上一级目录
void no_push();调用no_push()后,即便下一个元素是目录类型也不进入


示例代码,得到指定目录下的所有文件名(和上例作用相同):

  1. void find_file2( const fs::path & dir_path )
  2. {
  3.     fs::recursive_directory_iterator end_itr; // 缺省构造生成一个结束迭代器
  4.     for ( fs::recursive_directory_iterator itr( dir_path );
  5.         itr != end_itr;
  6.         ++itr )
  7.     {
  8.         std::cout << itr.level() << *itr << std::endl;
  9.     }



以下面的简单情况为例:您需要确定某个文件是否是 Directory 类型。在 Microsoft® Windows® 平台中,可以通过调用 GetAttributes 库函数(在 windows.h 头文件中定义)进行此操作:

DWORD GetFileAttributes (LPCTSTR lpFileName);

对于目录,所得到的结果应该为 FILE_ATTRIBUTE_DIRECTORY,而您的代码必须检查是否为此结果。在 UNIX® 和 Linux® 平台上,可以通过使用 stat 或 fstat 函数及 sys/stat.h 中定义的 S_ISDIR 宏来实现相同的功能。您还必须理解 stat 结构。下面是对应的代码:

#include <sys/stat.h>
#include <stdio.h>
int main()
  {
  struct stat s1;
  int status = stat(<const char* denoting pathname>, &s1);
  printf(“Path is a directory : %d\n”, S_ISDIR(s1.st_mode));
  return 0;
  }

对于 I/O 操作较多的程序,这样的不一致就意味着需要进行大量的工程工作才能在平台间移植代码。正是因为这个原因,我们才引入了 Boost Filesystem Library。这个广泛使用的库提供了安全、可移植且易用的 C++ 接口,用于执行文件系统操作。可以从 Boost站点免费下载此库。

使用 boost::filesystem 的第一个程序

在深入研究 Boost Filesystem Library 的更多细节之前,请看一下清单 1 中所示的代码;此代码使用 Boost API 确定某个文件的类型是否为 Directory。

清单 1. 用于确定某个文件的类型是否为 Directory 的代码
#include <stdio.h>
#include “boost/filesystem.hpp”
int main()
  {
  boost::filesystem::path path("/usr/local/include"); // random pathname
  bool result = boost::filesystem::is_directory(path);  
  printf(“Path is a directory : %d\n”, result);
  return 0;
  }

此代码非常明了易懂,您并不需要了解任何系统特定的例程。此代码经过验证,能在不用修改的情况下在 gcc-3.4.4 和 cl-13.10.3077 上成功编译。

了解 Boost path 对象

了解 Boost Filesystem Library 的关键是 path 对象,因为 Filesystem Library 中定义的多个例程都要对相应的 path 对象操作。文件系统路径通常依赖于操作系统。例如,众所周知,UNIX 和 Linux 系统使用正斜杠 ( /) 字符作为目录分隔符,而 Windows 将反斜杠 (\) 字符用于类似的用途。boost::filesystem::path 旨在准确地抽象此特性。path 对象可以通过多种方式进行初始化,最常见的方式是使用 char* 或 std::string 进行初始化,如清单 2 中所示。

清单 2. 创建 Boost path 对象的方法
path(); // empty path 
path(const char* pathname); 
path(const std::string& pathname);
path(const char* pathname, boost::filesystem::path::name_check checker); 
path(const char* pathname, boost::filesystem::path::name_check checker);

在初始化 path 对象时,可以采用本机格式或可移植操作系统接口(Portable Operating System Interface,POSIX)委员会定义的可移植格式提供 PATHNAME 变量。这两种方法在实际中各有优缺点。考虑以下情况:您希望操作软件所创建的目录,此目录在 UNIX 和 Linux 系统上位于 /tmp/mywork,而在 Windows 上位于 C:\tmp\mywork。可以采用多种方法处理问题。清单 3 显示了面向本机格式的方法。

清单 3. 使用本机格式初始化 path
#ifdef UNIX
boost::filesystem::path path("/tmp/mywork");
#else
boost::filesystem::path path("C:\\tmp\\mywork ");
#endif

需要单个 #ifdef 来按操作系统初始化 path 对象。不过,如果您喜欢使用可移植格式,请参见清单 4

清单 4. 使用可移植格式初始化 path
boost::filesystem::path path("/tmp/mywork");

请注意,path::name_check 指的是一个名称检查函数原型。如果其参数输入 PATHNAME 对于特定的操作系统或文件系统有效,名称检查函数将返回“True”。Boost Filesystem Library 提供了多个名称检查函数,而且也欢迎您提供自己的变体。常用的名称检查函数是 Boost 提供的 portable_posix_name 和 windows_name

path 成员函数概述

path 对象提供了多个成员方法。这些成员例程并不会修改文件系统,但会根据 path 名称提供有用的信息。此部分提供了其中几个例程的概述:

  • const std::string& string( )此例程会返回用于初始化 path 的字符串的副本,其格式符合 path 语法规则。
  • std::string root_directory( )在提供了路径的情况下,此 API 将返回根目录,否则将返回空字符串。例如,如果路径包含 /tmp/var1,则此例程将返回 /,即 UNIX 文件系统的根。不过,如果路径是相对路径,如 ../mywork/bin,此例程将返回空字符串。
  • std::string root_name( )在给定从文件系统根目录开始的路径的情况下,此例程将返回包含 PATHNAME 的第一个字符的字符串。
  • std::string leaf( )在给定绝对路径名称(例如,/home/user1/file2)的情况下,此例程将提供与文件名称对应的字符串(即 file2)。
  • std::string branch_path( )这是与 leaf 互补的例程。在给定路径的情况下,将会返回其构造所用的所有元素(除了最后一个元素)。例如,对于使用 /a/b/c 初始化的 path,path.branch_path( ) 将返回 /a/b。对于包含单个元素的路径,如 c,此例程将返回空字符串。
  • bool empty( )如果 path 对象包含空字符串(例如 path path1("")),则此例程将返回 True。
  • boost::filesystem::path::iterator此例程用于遍历 path 的各个元素。请看清单 5 所示的代码。
    清单 5. 使用 path::iterator(begin 和 end 接口)
    #include <iostream>
    #include “boost/filesystem.hpp”
    int main()
      {
      boost::filesystem::path path1("/usr/local/include"); // random pathname
      boost::filesystem::path::iterator pathI = path1.begin();
      while (pathI != path1.end())
        {
        std::cout << *pathI << std::endl;
        ++pathI;
        }
      return 0;
      }
     
    // result: 1

    上述程序的输出依次是 /usrlocalinclude,代表了该目录的层次结构。

  • path operator / (char* lhs, const path& rhs)此例程是 path 的非成员函数。它将返回使用 lhs 和 rhs 形成的路径的串联值。它将自动插入 / 作为路径分隔符,如清单 6 中所示。
    清单 6. 路径字符串的串联
    #include <iostream>
    #include “boost/filesystem.hpp”
    int main()
      {
      boost::filesystem::path path1("/usr/local/include"); // random pathname
      boost::filesystem::path::iterator pathI = path1.begin();
      while (pathI != path1.end())
        {
        std::cout << *pathI << std::endl;
        ++pathI;
        }
      return 0;
      }
     
    // result: 1

错误处理

文件系统操作经常遇到意外的问题,Boost Filesystem Library 将使用 C++ 异常报告运行时错误。boost::filesystem_error 类派生自 std::runtime_error 类。库中的函数使用 filesystem_error 异常报告操作错误。与不同的可能错误类型对应,Boost 头文件定义了相应的错误代码。用户代码通常驻留在 try...catch 块内,使用 filesystem_error 异常来报告相关错误消息。清单 7 提供了重命名文件的小示例,在 from 路径中的文件不存在时引发异常。

清单 7. Boost 中的错误处理
#include <iostream>
#include “boost/filesystem.hpp”
int main()
  {
  try {
  boost::filesystem::path path("C:\\src\\hdbase\\j1"); 
  boost::filesystem::path path2("C:\\src\\hdbase\\j2"); 
  boost::filesystem::rename(path, path2);
  }
  catch(boost::filesystem::filesystem_error e) { 
  // do the needful 
  }    
  return 0;
  }

Boost Filesystem Library 中的函数类别

boost::filesystem 提供了不同类别的函数:有些函数(如 is_directory)用于查询文件系统,而其他函数(如create_directory)则主动对文件系统进行修改。根据各自功能的不同,这些函数可以大略归入以下类别:

  • 属性函数:提供杂项信息,如文件大小、磁盘使用量等。
  • 文件系统操作函数:用于创建常规文件、目录和符号链接;复制和重命名文件;提供删除功能。
  • 实用工具:测试文件的扩展名等。
  • 杂项常规函数:以编程方式更改文件扩展名等。

属性函数

Boost Filesystem Library 包括以下属性函数:

  • uintmax_t file_size(const path&)返回常规文件的大小(以字节为单位)
  • boost::filesystem::space_info space(const path&)接受路径作为输入,并返回定义如下的 space_info 结构:
    struct space_info { 
      uintmax_t capacity;
      uintmax_t free;
      uintmax_t available;
    };

    根据文件系统所属的磁盘分区,此流程将对该分区的所有目录返回相同的磁盘使用量统计数据(以字节为单位)。例如,对于 C:\src\dir1 和 C:\src\dir2,都会返回相同的磁盘使用数据。

  • std::time_t last_write_time(const path&)返回文件的最后修改时间。
  • void last_write_time(const path&, std::time_t new_time)修改文件的最后修改时间。
  • const path& current_path( )返回程序的当前工作目录的完整路径(注意,此路径与最初运行程序的路径可能不同,因为可能采用编程方式更改目录)。

文件系统操作函数

这组函数负责进行新文件和目录创建、文件删除等操作:

  • bool create_directory(const path&)此函数使用给定的路径名称创建目录。(请注意,如果 PATHNAME 本身包含无效字符,则结果经常是由平台定义的。例如,在 UNIX 和 Windows 系统中,星号 (*)、问号 (?) 及其他此类字符视为无效,不能出现在目录名称中。)
  • bool create_directories(const path&)与创建单个目录相对,您可以使用此 API 创建目录树。例如,以目录树 /a/b/c 为例,必须在 /tmp 文件夹内创建此目录树。可调用此 API 完成任务,但使用相同的参数调用 create_directory 时将引发异常。
  • bool create_hard_link (const path& frompath, const path& topath)此函数在 frompath 和 topath 间创建硬链接。
  • bool create_symlink(const path& frompath, const path& topath)此函数在 frompath 和 topath 间创建符号(软)链接。
  • void copy_file(const path& frompath, const path& topath)将 frompath 引用的文件的内容和属性复制到topath 引用的文件中。例程expects a destination file to be absent;如果存在目标文件,则会引发异常。因此,此函数与 UNIX 中系统指定的 cp 命令并不等效。另外,此函数还预期 frompath 变量将引用正确的常规文件。请看以下示例:frompath 引用符号链接 /tmp/file1,而后者反过来引用文件 /tmp/file2;而 topath 可以为 /tmp/file3。在这种情况下,copy_file 将失败。这是此 API 与 cp 命令相比的另一个差别。
  • void rename(const path& frompath, const path& topath)此函数是用于重命名文件的 API。可以通过在topath 参数中指定完整路径名来同时重命名和更改文件的位置,如清单 8 中所示。
    清单 8. Boost 中的重命名功能
    #include <stdio.h>
    #include “boost/filesystem.hpp”
    int main()
      {
      boost::filesystem::path path("/home/user1/abc"); 
      boost::filesystem::rename(path, "/tmp/def");  
      return 0;
      }
     
    // abc is renamed def and moved to /tmp folder
  • bool remove(const path& p)此例程将尝试删除路径 p 所引用的文件或目录。对于目录的情况,如果目录的内容不为空,则此例程将引发异常。警告:此例程并不考虑所删除的内容,即使其他程序在访问同一文件也如此!
  • unsigned long remove_all(const path& p)此 API 尝试删除路径 p 所引用的文件或目录。与 remove 不同,此函数并不会特殊考虑不为空的目录。此函数是 UNIX rm –rf 命令的 Boost 对等项。

实用工具

Boost Filesystem Library 包含以下实用工具:

  • bool exists(const path&)此函数检查文件的扩展名。文件可以为任何类型:常规文件、目录、符号链接等等。
  • bool is_directory(const path&)此函数检查路径是否与目录对应。
  • bool is_regular(const path&)此函数检查普通文件(即此文件不是目录、符号链接、套接字或设备文件)。
  • bool is_other(const path&)通常,此函数检查设备文件(如 /dev/tty0)或套接字文件。
  • bool is_empty(const path&)如果路径与文件夹对应,此函数将检查文件夹是否为空,并据此返回“True”或“False”。如果路径与文件对应,此函数将检查文件的大小是否等于 0。对于文件的硬链接或符号链接的情况,此 API 将检查原始文件是否为空。
  • bool equivalent(const path1& p1, const path2& p2)此 API 非常实用,可用于比较相对路径和绝对路径名。请看清单 9
    清单 9. 测试两个路径是否等效
    #include <stdio.h>
    #include “boost/filesystem.hpp”
    int main()
      {
      boost::filesystem::path path1("/usr/local/include"); // random pathname
      boost::filesystem::path path2("/tmp/../usr/local/include");
      bool result = boost::filesystem::is_equivalent(path1, path2);  
      printf(“Paths are equivalent : %d\n”, result);
      return 0;
      }
     
    // result: 1
  • path system_complete(const path&)此函数是与 bool equivalent(const path1& p1, const path2& p2)同一系列的另一个 API。在给定当前工作目录中任意文件路径的情况下,此 API 将返回该文件的绝对路径。例如,如果用户位于目录 /home/user1 并查询文件 ../user2/file2,此函数将返回 /home/user2/file2,即文件 file2 的完整路径名。

杂项函数

Boost Filesystem Library 包括以下杂项函数:

  • std::string extension(const path&)此函数以前面带句点 (.) 的形式返回给定文件名的扩展名。例如,对于文件名为 test.cpp 的文件,extension 将返回 .cpp。对于文件没有扩展名的情况,此函数将返回空字符串。对于隐藏文件(即 UNIX 系统中文件名以 . 开始的文件),此函数将相应地计算扩展名类型或返回空字符串(因此,对于 .test.profile,此例程将返回.profile)。
  • std::string basename(const path&)这是与 extension 互补的例程。它将返回文件名中 . 之前的字符串。请注意,即使提供了绝对文件名,此 API 仍然仅会返回属于文件名的直接部分,如清单 10 中所示。
    清单 10. 使用 boost::basename
    #include <stdio.h>
    #include <cstring>
    #include “boost/filesystem.hpp”
    use namespace std;
    int main()
      {
      boost::filesystem::path path1("/tmp/dir1/test1.c "); 
      boost::filesystem::path path2("/tmp/dir1/.test1.profile");
      string result1 = boost::filesystem::basename (path1);  
      string result2 = boost::filesystem::basename (path2);
      printf(“Basename 1: %s  Basename2 : %s\n”, result1.c_str(), result2.c_str());
      return 0;
      }
     // result: Basename1: test1 Basename2: .test1
  • std::string change_extension(const path& oldpath, const std::string new_extension)此 API 将返回反映更改后的名称的新字符串。请注意,与 oldpath 对应的文件保持不变。这只是一个常规函数。另请注意,您必须显式地在扩展名中指定。例如,change_extension("test.c", "so") 会得到 testso,而不是 test.so

结束语

本文提供了 Boost Filesystem Library 的简单概述。不应将本文视为 Boost 中的整个文件系统接口的综合文档。并未讨论此 API 集的内部情况,也没有讨论这些 API 在非 UNIX 或 Windows 平台(如 VMS)中的细节。有关文件系统的更多信息,请参见参考资料

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值