天天看点

BOOST 之filesystem, path

目录[-]

<code>c++</code> 语言(实际上是 <code>c++</code> 标准)的最常见问题之一是,缺乏定义良好的库来帮助处理文件系统查询和操作。由于这个原因,程序员不得不使用本机操作系统提供的应用程序编程接口(application

program interfaces,api),而这使得代码不能在平台之间移植。以下面的简单情况为例:您需要确定某个文件是否是 directory 类型。在

microsoft? windows? 平台中,可以通过调用 <code>getattributes</code> 库函数(在

windows.h 头文件中定义)进行此操作:

对于目录,所得到的结果应该为 file_attribute_directory,而您的代码必须检查是否为此结果。在 unix? 和 linux?

平台上,可以通过使用 <code>stat</code> 或 <code>fstat</code> 函数及

sys/stat.h 中定义的 s_isdir

宏来实现相同的功能。您还必须理解 <code>stat</code> 结构。下面是对应的代码:

对于 i/o 操作较多的程序,这样的不一致就意味着需要进行大量的工程工作才能在平台间移植代码。正是因为这个原因,我们才引入了 boost

filesystem

library。这个广泛使用的库提供了安全、可移植且易用的 <code>c++</code> 接口,用于执行文件系统操作。可以从  站点免费下载此库。

在深入研究 boost filesystem library 的更多细节之前,请看一下 中所示的代码;此代码使用 boost api 确定某个文件的类型是否为 directory。

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

上成功编译。

了解 boost filesystem library 的关键是 <code>path</code> 对象,因为 filesystem

library

中定义的多个例程都要对相应的 <code>path</code> 对象操作。文件系统路径通常依赖于操作系统。例如,众所周知,unix 和

linux 系统使用正斜杠 (<code> /</code>) 字符作为目录分隔符,而 windows 将反斜杠 (<code>\</code>)

字符用于类似的用途。<code>boost::filesystem::path</code> 旨在准确地抽象此特性。<code>path</code> 对象可以通过多种方式进行初始化,最常见的方式是使用 <code>char*</code> 或<code>std::string</code> 进行初始化,如 中所示。

在初始化 <code>path</code> 对象时,可以采用本机格式或可移植操作系统接口(portable operating

system interface,posix)委员会定义的可移植格式提供 pathname

变量。这两种方法在实际中各有优缺点。考虑以下情况:您希望操作软件所创建的目录,此目录在 unix 和 linux 系统上位于 /tmp/mywork,而在

windows 上位于 c:\tmp\mywork。可以采用多种方法处理问题。 显示了面向本机格式的方法。

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

请注意,<code>path::name_check</code> 指的是一个名称检查函数原型。如果其参数输入 pathname

对于特定的操作系统或文件系统有效,名称检查函数将返回“true”。boost filesystem library

提供了多个名称检查函数,而且也欢迎您提供自己的变体。常用的名称检查函数是 boost

提供的<code>portable_posix_name</code> 和 <code>windows_name</code>。

<code>path</code> 对象提供了多个成员方法。这些成员例程并不会修改文件系统,但会根据 path

名称提供有用的信息。此部分提供了其中几个例程的概述:

<code>const std::string&amp; string( )</code>:此例程会返回用于初始化

path 的字符串的副本,其格式符合 path 语法规则。

<code>std::string root_directory( )</code>:在提供了路径的情况下,此

api 将返回根目录,否则将返回空字符串。例如,如果路径包含/tmp/var1,则此例程将返回 <code>/</code>,即

unix 文件系统的根。不过,如果路径是相对路径,如 ../mywork/bin,此例程将返回空字符串。

<code>std::string root_name( )</code>:在给定从文件系统根目录开始的路径的情况下,此例程将返回包含 pathname 的第一个字符的字符串。

<code>std::string leaf( )</code>:在给定绝对路径名称(例如,/home/user1/file2)的情况下,此例程将提供与文件名称对应的字符串(即

file2)。

<code>std::string branch_path( )</code>:这是与 <code>leaf</code> 互补的例程。在给定路径的情况下,将会返回其构造所用的所有元素(除了最后一个元素)。例如,对于使用 /a/b/c 初始化的

path,<code>path.branch_path( )</code> 将返回 <code>/a/b</code>。对于包含单个元素的路径,如 c,此例程将返回空字符串。

<code>bool empty( )</code>:如果 path

对象包含空字符串(例如 path path1("")),则此例程将返回 true。

<code>boost::filesystem::path::iterator</code>:此例程用于遍历

path 的各个元素。请看 所示的代码。

上述程序的输出依次是 <code>/</code>、<code>usr</code>、<code>local</code>、<code>include</code>,代表了该目录的层次结构。

<code>path operator / (char* lhs, const path&amp; rhs)</code>:此例程是 <code>path</code> 的非成员函数。它将返回使用 <code>lhs</code> 和 <code>rhs</code> 形成的路径的串联值。它将自动插入 <code>/</code> 作为路径分隔符,如 中所示。

文件系统操作经常遇到意外的问题,boost filesystem library

将使用 <code>c++</code> 异常报告运行时错误。<code>boost::filesystem_error</code> 类派生自<code>std::runtime_error</code> 类。库中的函数使用 <code>filesystem_error</code> 异常报告操作错误。与不同的可能错误类型对应,boost

头文件定义了相应的错误代码。用户代码通常驻留在 <code>try...catch</code> 块内,使用 <code>filesystem_error</code> 异常来报告相关错误消息。 提供了重命名文件的小示例,在 <code>from</code> 路径中的文件不存在时引发异常。

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

属性函数:提供杂项信息,如文件大小、磁盘使用量等。

文件系统操作函数:用于创建常规文件、目录和符号链接;复制和重命名文件;提供删除功能。

实用工具:测试文件的扩展名等。

杂项常规函数:以编程方式更改文件扩展名等。

boost filesystem library 包括以下属性函数:

<code>uintmax_t file_size(const path&amp;)</code>:返回常规文件的大小(以字节为单位)

<code>boost::filesystem::space_info space(const path&amp;)</code>:接受路径作为输入,并返回定义如下的 <code>space_info</code> 结构:

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

c:\src\dir2,都会返回相同的磁盘使用数据。

<code>std::time_t last_write_time(const path&amp;)</code>:返回文件的最后修改时间。

<code>void last_write_time(const path&amp;, std::time_t new_time)</code>:修改文件的最后修改时间。

<code>const path&amp; current_path( )</code>:返回程序的当前工作目录的完整路径(注意,此路径与最初运行程序的路径可能不同,因为可能采用编程方式更改目录)。

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

<code>bool create_directory(const path&amp;)</code>:此函数使用给定的路径名称创建目录。(请注意,如果 pathname

本身包含无效字符,则结果经常是由平台定义的。例如,在 unix 和 windows 系统中,星号 (<code>*</code>)、问号

(<code>?</code>) 及其他此类字符视为无效,不能出现在目录名称中。)

<code>bool create_directories(const path&amp;)</code>:与创建单个目录相对,您可以使用此 api 创建目录树。例如,以目录树 /a/b/c 为例,必须在

/tmp 文件夹内创建此目录树。可调用此 api

完成任务,但使用相同的参数调用 <code>create_directory</code> 时将引发异常。

<code>bool create_hard_link (const path&amp; frompath, const path&amp; topath)</code>:此函数在 <code>frompath</code> 和 <code>topath</code> 间创建硬链接。

<code>bool create_symlink(const path&amp; frompath, const path&amp; topath)</code>:此函数在 <code>frompath</code> 和 <code>topath</code> 间创建符号(软)链接。

<code>void copy_file(const path&amp; frompath, const path&amp; topath)</code>:将 <code>frompath</code> 引用的文件的内容和属性复制到 <code>topath</code> 引用的文件中。例程expects

a destination file to be absent;如果存在目标文件,则会引发异常。因此,此函数与 unix

中系统指定的 <code>cp</code> 命令并不等效。另外,此函数还预期 <code>frompath</code> 变量将引用正确的常规文件。请看以下示例:<code>frompath</code> 引用符号链接

/tmp/file1,而后者反过来引用文件 /tmp/file2;而 <code>topath</code> 可以为

/tmp/file3。在这种情况下,<code>copy_file</code> 将失败。这是此 api

与 <code>cp</code> 命令相比的另一个差别。

<code>void rename(const path&amp; frompath, const path&amp; topath)</code>:此函数是用于重命名文件的

api。可以通过在 <code>topath</code> 参数中指定完整路径名来同时重命名和更改文件的位置,如 中所示。

<code>bool remove(const path&amp; p)</code>:此例程将尝试删除路径 p 所引用的文件或目录。对于目录的情况,如果目录的内容不为空,则此例程将引发异常。警告:此例程并不考虑所删除的内容,即使其他程序在访问同一文件也如此!

<code>unsigned long remove_all(const path&amp; p)</code>:此

api

尝试删除路径 p 所引用的文件或目录。与 <code>remove</code> 不同,此函数并不会特殊考虑不为空的目录。此函数是

unix <code>rm –rf</code> 命令的 boost 对等项。

boost filesystem library 包含以下实用工具:

<code>bool exists(const path&amp;)</code>:此函数检查文件的扩展名。文件可以为任何类型:常规文件、目录、符号链接等等。

<code>bool is_directory(const path&amp;)</code>:此函数检查路径是否与目录对应。

<code>bool is_regular(const path&amp;)</code>:此函数检查普通文件(即此文件不是目录、符号链接、套接字或设备文件)。

<code>bool is_other(const path&amp;)</code>:通常,此函数检查设备文件(如

/dev/tty0)或套接字文件。

<code>bool is_empty(const path&amp;)</code>:如果路径与文件夹对应,此函数将检查文件夹是否为空,并据此返回“true”或“false”。如果路径与文件对应,此函数将检查文件的大小是否等于

0。对于文件的硬链接或符号链接的情况,此 api 将检查原始文件是否为空。

<code>bool equivalent(const path1&amp; p1, const path2&amp; p2)</code>:此 api 非常实用,可用于比较相对路径和绝对路径名。请看:

<code>path system_complete(const path&amp;)</code>:此函数是与 <code>bool equivalent(const path1&amp; p1, const path2&amp; p2)</code> 同一系列的另一个 api。在给定当前工作目录中任意文件路径的情况下,此 api

将返回该文件的绝对路径。例如,如果用户位于目录 /home/user1 并查询文件

../user2/file2,此函数将返回 <code>/home/user2/file2</code>,即文件 file2

的完整路径名。

boost filesystem library 包括以下杂项函数:

<code>std::string extension(const path&amp;)</code>:此函数以前面带句点 (<code>.</code>)

的形式返回给定文件名的扩展名。例如,对于文件名为 test.cpp 的文件,<code>extension</code> 将返回 <code>.cpp</code>。对于文件没有扩展名的情况,此函数将返回空字符串。对于隐藏文件(即

unix

系统中文件名以 <code>.</code> 开始的文件),此函数将相应地计算扩展名类型或返回空字符串(因此,对于 .test.profile,此例程将返回 <code>.profile</code>)。

<code>std::string basename(const path&amp;)</code>:这是与 <code>extension</code> 互补的例程。它将返回文件名中 <code>.</code> 之前的字符串。请注意,即使提供了绝对文件名,此

api 仍然仅会返回属于文件名的直接部分,如 中所示。

<code>std::string change_extension(const path&amp; oldpath, const std::string new_extension)</code>:此 api

将返回反映更改后的名称的新字符串。请注意,与 <code>oldpath</code> 对应的文件保持不变。这只是一个常规函数。另请注意,您必须显式地在扩展名中指定点。例如,<code>change_extension("test.c", "so")</code> 会得到 <code>testso</code>,而不是 <code>test.so</code>。

本文提供了 boost filesystem library 的简单概述。不应将本文视为 boost 中的整个文件系统接口的综合文档。并未讨论此 api

集的内部情况,也没有讨论这些 api 在非 unix 或 windows 平台(如 vms)中的细节。有关文件系统的更多信息,请参见。