原文链接:http://www.usidcbbs.com/simple/?t1883.html
今天开始写作boost库指南系列文章了,我个人比较熟的就是这个filesystem库,当然要从这里先开始。这系列指南只是对初学的一个快速指南,没有深入学习,当然我个人水平也不敢说“深入”二字。
C++ 程序一直有一个方面不能做可移植性,尽管标准库有几个函数用于操作与文件系统相关的任务,但是这几个函数作用相对我们日常对文件系统操作的需求来说真是杯水车薪,所以对目录、路径、文件元信息的操作一直难以做可移植性。然而对于现在的程序来说,可移植性极端重要,谁也不保证他写程序不要某一天要移植更一个系统中去,可能这个系统现在大家还很少听说。
boost.filesystem 为大家提供了一个选择。boost.filesystem以实现可移植的文件系统的操作为目标,通过精心设计一个中间概念来完成大多数可移植的文件系统的操作,这个中间层试图独立于所有的具体文件系统,然后把操作任务映射到这个中间层。当然这个中间层可能与现有的文件系统有最大的相似之处。本文不试图去讲述这个中间层,因为针对绝大部分情况,我们使用boost.filesystem不需要知道这个中间层。
下面我正式开始这个指南,这次好像扯得太远了。
基础知识
这里我们讲述一些使用库的基础的准备的知识。
filesystem 库提供了两个头文件,一个是 ,这个头文件包含主要的库内容。它提供了对文件系统的重要操作。同时它定义了一个类path,正如大家所想的,这个是一个可移植的路径表示方法,它是filesystem库的基础。
一个是 ,是对std::fstream的一个补充,使用可以使用类boost::path作为参数,从而使得filesystem库与标准库的关系更亲密。
由于文件系统对于大多数系统来说都是共享的,所以不同的进程可以同时操作同一个对象,因此filesysetm不提供这方面的特性保证。当然这种保证也是不可能的,或者至少昂贵的。
filesystem在任何时候,只要不能完成相应的任务,它都可能抛出 basic_filesystem_error异常,当然并不是总会抛出异常,因为在库编译的时候可以关闭这个功能。同时有两个函数提供了无异常版本,这是因为在任务不能完成时并非是异常。
filesystem 库的所有内容定义在boost名字空间的一个下级名字空间里,它叫boost::filesytem。在使用boost.filesytem之后,链接时需要加“-lboost_filesystem-mt”选项,因为这个需要额外的链接,并非一个纯头文件的库。 获得单独文件属性有了上面的准备知识,大家可以写一些简单的程序了。这篇文档主要作为一个入门的指南性的文档,所以会提供许多实例,或者说主要以实体来说明的boost.filesystem库的使用.
/*
* =====================================================================================
*
* Filename: filesystem.cpp
*
* Description: 简单C++,boost filesystem 指南
*
* Version: 1.0
* Created: 2009年08月17日 17时16分32秒
* Revision: none
* Compiler: gcc -Wall -Wextra filesystem.cpp -lboost_filesystem-mt
*
* Author: lgb (LiuGuangBao), [email protected]
* Company: easy99.org
*
* =====================================================================================
*/
#include
#include
#include
int main()
{
namespace bf=boost::filesystem;//简单别名
//filesystem中最基本的类型
bf::path path("/tmp/test");
//对当前的目录的操作
bf::path old_cpath=bf::current_path(); //取得当前目录
bf::path file_path = path / "file"; //path重载了 / 运算符
//判断文件存在性
if(bf::exists(path))
{
std::ofstream out(path.file_string().c_str());
if(!out) return 1;
out << "一个测试文件/n";
} else {
std::cout << path << "不存在/n";
//目录不存在,创建
bf::create_directory(path);
std::ofstream out(file_path.file_string().c_str());
if(!out) return 1;
out << "一个测试文件/n";
}
bf::current_path(path); //设置当前为/home
if(bf::is_regular_file(path))
{
std::cout << path << "是普通文件/n";
std::cout << path << ": 大小为" << bf::file_size(path) <<'/n';
bf::create_symlink(file_path, "/tmp/test/file-symlink");
}
bf::current_path(old_cpath);
bf::remove(file_path);//删除文件file_path
bf::remove_all(path);//递归地删除
return 0;
}
上面的示例我们在Linux在测试通过,因为使用的是Linux系统。它首先创建一些东西,最后又把这些东西删除了,恢复原样了。
filesystem库使用经验
文件系统不具有许多特性与我们日常编写的程序不一样,标准库没有提供一个filesystem的原因就在于此,这个特殊性表现在:
文件系统是操作系统级别上的全局性,即文件系统中的操作可以在多个进程中异步进行,这可能引起许多问题,也就是说文件系统不是串行系统。
文件系统具有很大的系统相关性,不同的操作系统提供了不同的文件系统,相同的操作系统也可以存在众多区别。这使得编写具有可移植的文件系统相关程序很困难,这需要足够多的小心与细致。
不要使用绝对路径,因为绝对路径系统相关性太强了,所以不可能在中间层透明地完成;应该使用相对路径。
boost::filesystem系统地定义了一个中间层,并且做到尽可能自由,但是有些问题是无法避免的。如UNIX系统存在符号链接的概念,而Windows中不存在,所以当你使用符号链接的时候就说明你不可能做到可移植性。
缺乏定义良好的、用于处理文件系统操作的库,这一直是 C++
语言存在的一个问题。过去,程序员必须使用本机 API 来解决此问题。通过本文您将了解一个提供安全、可移植且易用的 C++
接口来促进文件系统操作的库:Boost Filesystem Library。
C++
语言(实际上是 C++
标准)的最常见问题之一是,缺乏定义良好的库来帮助处理文件系统查询和操作。 由于这个原因,程序员不得不使用本机操作系统提供的应用程序编程接口(Application Program Interfaces,API),而这使得代码不能在平台之间移植。以下面的简单情况为例:您需要确定某个文件是否是 Directory 类型。在 Microsoft® Windows® 平台中,可以通过调用 GetAttributes
库函数(在 windows.h 头文件中定义)进行此操作:
DWORD GetFileAttributes (LPCTSTR lpFileName);
对于目录,所得到的结果应该为 FILE_ATTRIBUTE_DIRECTORY,而您的代码必须检查是否为此结果。在 UNIX® 和 Linux® 平台上,可以通过使用 stat 或 fstat 函数及 sys/stat.h 中定义的 S_ISDIR 宏来实现相同的功能。您还必须理解 stat 结构。下面是对应的代码:
#include
#include
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
#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
#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
上述程序的输出依次是 /、usr、local、include,代表了该目录的层次结构。
path operator / (char* lhs, const path& rhs):此例程是 path 的非成员函数。它将返回使用 lhs 和 rhs 形成的路径的串联值。它将自动插入 / 作为路径分隔符,如清单 6 中所示。
清单 6. 路径字符串的串联
#include
#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
#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
#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
#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
#include
#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)中的细节。有关文件系统的更多信息,请参见参考资料。
/*
* @file FilePath.hpp
*
* 项目描述: 构造游戏引擎
* 文件描述: 游戏文件系统类
* 适用平台: Windows/Lunix/Unitx/..
*
* 作者: ccsdu2004
* 电子邮件: [email protected]
* 网址 : www.gaimo.net/ hi/csdn.net/ccsdu2004
* 创建日期: 2009-04-17
* 修改日期: ..
*
*/
#ifndef G_UTIL_FILEPATH_HPP
#define G_UTIL_FILEPATH_HPP
#include
#include
#include
#include
#include
using namespace std;
using namespace boost;
using namespace boost::filesystem;
namespace g
{
namespace file
{
class __declspec(dllexport) FilePath : public noncopyable
{
public:
//参数为文件夹路径
FilePath(string filepath);
~FilePath(){}
public:
inline void find_in_sub_path(bool flag = false){subpath = flag;}
//lie that: *.map3 *.wav ...
void set_suffix(const string &suffixs);
void get_files(vector
&files);
private:
void find(boost::filesystem::path p);
private:
string filepath;
bool subpath;
vector file;
set suffix;
bool usesf;
};
}
}
#endif
#include
#include
#include
#include "FilePath.hpp"
using namespace boost::algorithm;
namespace g
{
namespace file
{
FilePath::FilePath(string _filepath): filepath(_filepath),
subpath(false),
usesf(false)
{}
void FilePath::set_suffix(const string &suffixs)
{
string temp(suffixs);
to_lower(temp);
tokenizer<> sf(temp);
for(tokenizer<>::iterator itr = sf.begin(); itr != sf.end();++itr)
{
suffix.insert(*itr);
}
usesf = true;
}
void FilePath::get_files(vector
&files)
{
boost::filesystem::path _filepath(filepath,boost::filesystem::native);
find(_filepath);
files = file;
}
void FilePath::find(boost::filesystem::path p)
{
try
{
if(boost::filesystem::exists(p) == true)
{
boost::filesystem::directory_iterator item_begin(p);
boost::filesystem::directory_iterator item_end;
for(;item_begin != item_end; item_begin++ )
{
if (boost::filesystem::is_directory( * item_begin) == true && subpath == true)
{
// (*item_begin)
//(*itr)
find(item_begin->path());
}
else
{
string filename =item_begin->leaf();
if(usesf == true)
{
to_lower(filename);
set ::iterator itr = suffix.begin();
while(itr != suffix.end())
{
if(ends_with(filename, *itr)== true)
file.push_back(filename);
itr ++;
}
}
else
{
file.push_back(filename);
}
}
}
}
}
catch(boost::filesystem::filesystem_error e)
{
}
}
}
}
#include
#include
/// 遍历目录strPath中的所有文件
int GetAllFile(const string &strPath)
{
if ( strPath.size() < 2 )
{
return 0;
}
namespace fs = boost::filesystem;
// 得到配置文件夹.
fs::path full_path( fs::initial_path() );
full_path = fs::system_complete( fs::path(strPath,fs::native ) );
unsigned long file_count = 0;
unsigned long dir_count = 0;
unsigned long err_count = 0;
if ( !fs::exists( full_path ) )
{
string strMsg = "找不到文件目录,请检查该目录是否存在: ";
strMsg.append(full_path.native_file_string());
return -1;
}
// 遍历指定的文件夹,得到所有的文件名.
if( fs::is_directory( full_path ) )
{
fs::directory_iterator end_iter;
for ( fs::directory_iterator dir_itr( full_path );
dir_itr != end_iter; ++dir_itr )
{
try
{
if( fs::is_directory( *dir_itr ) )
{
string strSubDir(full_path.native_directory_string()) ;
strSubDir.append( "// ");
strSubDir.append(dir_itr-> leaf());
GetAllFile(strSubDir); // 如果有子目录,则递归遍历.
}
else
{
// 先组成包括完整路径的文件名
string strFileName(full_path.native_directory_string());
strFileName.append( "// ");
strFileName.append(dir_itr-> leaf());
//判断文件是否为XML配置文件
if (false == CheckIsXMLFile(strFileName))
{
continue;
}
fs::path full_file( fs::initial_path() );
full_file = fs::system_complete(fs::path(strFileName, fs::native));
//加载解析文件中的信息.
//readFileInfo(full_file.native_directory_string());
}
}
catch( const std::exception & ex )
{
++err_count;
}
}// <--for()
loggerXML-> debug( "成功遍历所有设备配置文件. ");
}
else // must be a file
{
string strMsg = full_path.native_file_string();
strMsg.append( ",不是文件目录. ");
return -1;
}
return err_count;
}
boost filesystem library能使c++程序员写出与操作系统平台无关的操作文件或者目录的代码,本文就是与此相关的。
首先看一下传统的用来操作文件的cpp代码:
#include
#include
#include
int main()
{
struct stat st;
if(lstat("first.cpp",&st)==-1 &&errno==ENOENT)
std::cout<<"the file doesn't exist./n";
else
std::cout<<"the file exists./n"
}
上面的代码能在绝大多数 GNU/linux平台上面运行,但是在windows System上则不能运行,其中一种常用的写出可移植代码的方法是使用#ifdef,当操作系统不同时来描述不同的部分另一种方式则是创建一个中间层,对不同的操作系统提供单一的接口,Boost则提供了这样一个接口,它对Windows和其他满足POSIX标准的系统都提供了一个统一的接口。另一个好处就是这也满足了c++的哲学,为了健壮性,在大多数时候,尽量使用标准库,当然Boost正是这样一个库。
下面的代码则是使用Boost库实现的代码:
#include
#include
namespace bf=boost::filesystem; //标记一
int main()
{
bf::path p("first.cpp");
if(bf::exists(p))
std::cout<
<<
"exists./n";
else
std::cout<
<<
"doesn't exist./n";
}
标记一是为Boost库的filesyste库设定一个别名,使用时方便一些
boost::filesystem文件库包含了很多操作文件,目录的函数,比如:exists(),is_directory()等,path是一种类型,他使对文件路径的表示做到了平台无关。
exists()以路径为参数,如果文件存在的话则返回true,否则false,而函数leaf()则返回文件名,比如p为/home/opunia/tests/first.cpp,则p.leaf()返回first.cpp。
至于怎么样编译含有boost库的文件又是另外一回事清了,在linux下,也许是这样的:
g++ -Wall -o first first.cpp -lboost_filesystem
boost::filesystem里面有很多单独的函数,比如上面的path放在path.hpp里面,可是大多数情况下,我们并不包括头文件path.hpp,而是如同上面的代码所见的,使用operations.hpp,因为他包括了boost::filesystem下面的所有操作
下面是另外一个更详细的例子:
#include
#include
namespace bf=boost::filesystem;
int main()
{
bf::path p(second.cpp);
if(!bf::exists(p)){
std::cout<
<<
"doesn't exists./n";
return -1
}
if(bf::is_directory(p))
std::cout<
<<
"is a directory./n";
else if(bf::symbolic_link_exists(p))
std::cout<
<<
"is a symbolic link./n";
else
std::cout<
<<
"is a regular file./n";
std::cout<<"file size:"<
<
std::cout<<"last modification time:"<
std::cout<
}
下面是boost::filesystem库的一些例子,为了简便,把每个例子需要的头文件放在了一起,如下所示:
#include
#include
#include
namespace bfs=boost::filesystem;
文件的创建和删除
std::cout<<"Enter your choice:/n";
std::cout<<"1.Create folder/n2.Remove File./n3.Rename File/4.Copy File/n";
char ch;
std::cin>>ch;
std::string name,new_name;
switch(ch){
case '1':
std::cout<<"Enter folder name:";
std::cin>>name;
bfs::create_directory(bfs::path(name));
break;
case '2':
std::cout<<"Enter file name:";
std::cin>>name;
std::cout<<"Enter new name:";
std::cin>>new_name;
bfs::rename(name,new_name);
break;
case '3':
std::cout<<"Enter file name:";
std::cin>>name;
bfs::remove(bfs::path(name));
break;
case '4':
std::cout<<"Enter file name:";
std::cin>>name;
std::cout<<"Enter new name:";
std::cin>>new_name;
bfs::copy_file(name,new_name);
break;
}
std::cout<<"OPeration finished."<
在上面的代码中,使用了四个库函数:
bfs::create_directory(bfs::path(name));
bfs::rename(name,new_name);
bfs::remove(bfs::path(name));
bfs::copy_file(name,new_file);
他们的功能正如他们的名字所暗示的那样。
删除目录下的所有文件:
std::cout<<"Enter the name of the folder to empty:";
std::string name;
std::cin>>name;
bfs::remove_all(bfs::path(name));
std::cout<<"Operation completed."<
或者使用directory_iterator迭代器
如下所示:
bfs::path p("folder");
bfs::directory_iterator dir_iter(p),dir_end;
for(;dir_iter !=dir_end;++dir_iter){
std::cout<<(*dir_iter).leaf();
}
同样地(*dir_iter).leaf()等价于 dir_iter->leaf()
通过迭代器删除目下下的所有文件:
std::cout<<"Enter the name of the folder to empty:";
std::string name;
std::cin>>name;
bfs::path p(name);
if(!bfs::exists(p)||!bfs::is_directory(p))
{
std::cout<<"Invalid input."<
exit(-1);
}
bfs::directory_iterator dir_iter(p),dir_end;
for(;dir_iter!=dir_end;++dir_iter)
{
std::cout<<"Removing file:"<
leaf();
bfs::remove(*dir_iter);
}
std::cout<<"Operation COmpleted."<
一个搜寻某个具体文件的函数:
bool find_file(const bfs::path &dir_path,const std::string &file_name,bfs::path &pfound)
{
if(!exists(dir_path)||!is_directory(dir_path))
return false;
bfs::directory_iterator iter(dir_path),end_iter;
for(;iter!=end_iter;++iter)
{
if(bfs::is_directory(*iter))
{
if(find_file(*iter,file_name,pfound))
return true;
}
esle if(iter->leaf() == file_name)
{
pfound=*iter;
return true;
}
}
return false;
}
上面的函数用了一个递归对深层目录进行处理。当找到该文件时,返回true,否则返回false。
下面是一个简单的例举目录下文件的函数(ls|dir):
void sls(const bfs::path &p)
{
unsigned long fc=0,dc=0;
if(!bfs::exists(p))
std::cout<<"File Not Found:"< << "/n";
else if(!bfs::is_directory(p))
std::cout<<"/nFound:"< << "/n";
std::cout<<"In Directory:"< << "/n";
bfs::directory_iterator iter(p),end_iter;
for(;iter!=end_iter;++iter)
{
try
{
if(bfs::is_directory(*iter))
{
++dc;
std::cout<
leaf()<<
"[Directory]/n";
}
else
{
++fc;
std::cout<
leaf()<<
"/n";
}
}
catch(const std::exception &ex)
{
std::cout<
leaf()<<
":"<
<
}
std::cout<
<<
" "<
<
}
}
上面的代码,目录名后面加上了[Directory]标签,在代码的最后会显示出要显示的目录下的文件数和目录数,不过上面的代码没有考虑子目录的情况,上面只打印了文件的native_file_string()属性,还有is_symbolic_link(),file_size(),last_write_time()等属性。