/*FileSyatem 库的学习
------------------------------------------------------------------------------------------------------------库的使用方式
嵌入源码的形式:
#define BOOST_SYSTEN_NO_LIB
#define BOOST_FILESYSTEM_NO_LIB
#include<boost\filesystem.hpp>
-----------------------------------------------------------------------------------------------------------类摘要
filesystem 库的核心类是basic_path 通常我们不直接使用basic_path而是使用预定义的path和wpath
typedef basic_path<std::string,path_traits>path;
------------------------------------------------------------------------------------------------------------路径表示
posix 语法使用斜杠(/)来分隔文件名和目录名,点号(.)表示当前目录,双点号(..)表示上一级目录
path p1("./a_dir");
path p2("/usr/local/lib");
path也支持操作系统的原生路径表示比如windows下使用盘符分隔符和反斜杠(\):
path p3("c:\\temp\\test.text");
path p4("d:/boost/boostget");
空的构造函数创建一个空路径对象,不表示任何路径,成员函数empty可以判断路径是否为空
path p5;
assert(p.empty());
path 重载了operator/=可以使用普通路径一样用/来追加路径,成员函数append()也可以追加一个字符串序列
char str[]="the path is (/root).";
path p(str+13,str+14);
p/="etc";追加路径
string filename="xinetd.conf";
p.append(filename.begin(),file.end());
结果:p=/etc/xinetd.conf;
system_complete(p)返回路径在当前文件系统中的完整文件路径
--------------------------------------------------------------------------------------------------------------------可移植的文件名
filesystem提供了一系列的文件名检查函数可以根据系统命名规则判断一个文件字符串是否有效
portable_posix_name()和windows_name()分别检查文件名是否符合POSIX规范和windows规范
函数portable_name()判断名字是否是一个可移植的文件名但名字不能以点好或者连字符开头,允许表示当前目录的“。”和父目录“..”
protable_directory_name()包含了portable_name()并且要求名字不能出现点号
portable_file_name() 类似protable_directory_name()它要求文件名中最多有一个点号并且后缀名不能超过三个字符
filesystem 提供了一个native()函数它判断文件名是否符合本地文件系统名规则在windows等同于windows_name(),其他操作系统知识简单的判断文件名不是空格且不含斜杠
---------------------------------------------------------------------------------------------------------------------路径处理
path的成员函数string()返回标准格式的路径表示,directory_string()返回文件系统格式路径表示,parent_path(),stem(),filename()和extension()分别返回路径中的父路径,不含扩张名的全路径名,文件名和扩展名
is_complete()函数检测path是否是一个完整的路径(绝对路径),这需要依据具体的文件(操作系统)系统表示
root_name()和root_directory(),root_path()三个函数用于根目录的处理如果path中含有根那么他们分别返回根的名字,根目录和根路径
cout<<p.root_name()<<endl;
cout<<p.root_directory()<<endl;
cout<<p.root_path()<<endl;
这段代码在linux下输出一个空字符串和两个斜杠(/),如果path是如C:/xx/yyy的形式输出的会是 “C”,“/”,“C:/”
relative_path()返回path的相对路径相当于去掉了root_path()
根路径和相对路径的的四个函数都有对应的has_XXX()的形式,用来判断是否存在对应的路径
has_filename()和has_parent_path()用于判断路径是否有文件名或者父路径
p.has_root_name()
可以修改path函数:
remove_filename()可以移除路径中的最后文件名,变成纯路径
replace_extension()可以变更文件的扩展名
可以对两个path对象进行比较基于字典且对大小写敏感 < > == !=
-----------------------------------------------------------------------------------------------------------------------------迭代路径中的字符串
path还提供迭代器 begin()和end()
path p="/boost/tools/libs"
BOOST_AUTO(pos,p.begin());
while(pos!=p.end())
{
cout<<"["<<*pos<<"]";
++pos;
}
结果[/][boost][tools][libs]
如果path类提供的这些操作还不能满足要求可以使用boost库中的字符串库如string_algo
--------------------------------------------------------------------------------------------------------------------------------异常
异常类是个模板类basic_filesystem_error它是system库中system_error类的子类
我们通常应该使用这两个预定义的异常类
typedef basic_filesystem_error<path> filesystemerror
typedef basic_filesystem_error<path> wfilesystemerror
--------------------------------------------------------------------------------------------------------------------使用
下面的代码检查文件大小但是文件不存在
path p("c:/test.txt")
try
{
file_size(p);
}
catch(filesystem_error& e)
{
cout<<e.path1()<<endl;
cout<<e.what()<<endl;
}
----------------------------------------------------------------------------------------------------------------------------------------文件状态
filesystem库提供一个文件状态类file_status以及一组相关函数,用于检查文件的各种属性,如有是否存在是否是目录,是否是符号链接等
file_status的成员函数type()用于获取文件的状态他是一个枚举值通常我们不直接使用file_status而是使用使用相关的函数返回file_status对象
函数status(const Path&p)和symlink_status(const Path&p)测试路径p的状态结果可以type()如果路径不能解析则抛出异常
file_type是枚举值可以是以下值:
file_not_found 文件不存在
status_unknow 文件存在但状态未知
regular_file 是一个普通文件
directory_file 是一个目录
symlink_file 是一个连接文件
block_file 一块设备文件
character_file 一个字符设备文件
fifo_file 管道设备文件
socket_file socket设备文件
type_unknow 文件的类型未知
assert(status("d:/boost").type()==directory_file)
filesystem 库提供了一些便利的谓词函数is_XXX以简化文件状态的判断
assert(is_directory("d:/boost"))
大部分谓词函数望文只意比较特别的是is_other()和is_empty()但文件不是普通文件,目录或链接是,is_other()返回true
对于 empty若是目录则里边没文件时返回true,若是文件 大小问0是返回true
函数 equivalent()可比较两个目录实体是否是同一个
----------------------------------------------------------------------------------------------------------------------------------------文件属性
受到移植性的限制filesystem提供少量的文件属性操作
函数initial_path()函数返回程序启动时(进入main())的当前路径
函数current_path()返回当前路径它和initial_path()都是返回完整路径
函数file_size()以字节为单位返回文件的大小
函数last_write_time()返回文件最后修改时间是一个time_t 类型
函数space可以返回一个space_info它表明该路径下的磁盘空间分配情况
struct space_info
{
uintmax_t capacity;
uintmax_t free;
uintmax_t available;
}
space()函数可以这样使用
const int GBYTES=1024*1024*1024;
space_info si=space("d:/");
cout<<si.capacity/GBYTES<<endl;
cout<<si.available/GBYTES<<endl;
---------------------------------------------------------------------------------------------------------------------------------文件操作
创建目录 create_directory()
文件改名 rename()
文件删除 remove(),remove_all()可以递归删除所有文件对于remove使用时要加命名空间限制,否则vc环境下的函数会将其覆盖
文件拷贝 copy_file()
...........
------------------------------------------------------------------------------------------------------------------迭代目录
filesystem 库使用basic_directory_iterator可以迭代目录下所有文件
其预定义了两个迭代器类 directory_iterator 和wdirectroy_iterator
basic_directory_iterator迭代器返回的不是path对象而是basic_directory_entry对象,但是basic_directory_entry类定义了一个到path类的转换函数
可以使用path()返回路径
directory_iterator只能迭代本目录中的文件不支持深度遍历目录但是可以通过递归实现
void recursive_dir(const path& dir)
{
directory_iterator end;
for(directory_iterator pos(dir);pos!=end;++pos)
if(is_directory(*pos))
{
recursive_dir(*pos);
}
else
cout<<*pos<<endl;
}
basic_recursive_directory_iterator类提供了目录的遍历功能它比递归的调用directory_iterator效率要高
其基本功能和directory_iterator相似
通常我们使用其预定义的两个类 recursive_directory_iterator和wrecursive_directory_iterator
recursive_directory_iterator ++会使它返回目录中的下一个文件
成员函数:
level()返回当前目录深度 m_level,recursive_directory_iterator构造时m_level=0每深入一层m_level加1退出时减少1
pop()用于退出当前目录的遍历同时--mlevel,但迭代到一个目录no_push()可以让目录不参与遍历
使用recursive_directory_iterator遍历目录操作
recursive_directory_iterator end;
for(recursive_directory_iterator pos("d:/test");pos!=end;++pos)
cout<<"level:"<<pos.level()<<":"<<*pos<<endl;
使用no_push()让recursive_directory_iterator和directory_iterator行为相同:
directory_iterator end;
for(recursive_directory_iterator pos(dir);pos!=end;++pos)
if(is_directory(*pos))
{
pos.no_push();
}
else
cout<<*pos<<endl;
----------------------------------------------------------------------------------------------------------------------------------------------文件流操作
filesystem 库提供大量的文件系统操作方法,可以方便的操作文件或者目录,但他使用的是path对象C++标准库中的文件流类ifstream/ofstream/ftream只支持char*打开文件,因此使用时我们必须
调用path对象的string()方法然后把string转化为C字符串
path p("d:/boost/Readme.txt");
std::ifstream ifs(p.string().c_str());
filesystem 库在额外的头文件<boost/filesystem/fstream.hpp>中提供在命名空间boost::filesystem下的同文件流类他们可以如
标准文件流一样使用而且支持path对象
使用方法:
#include<>boost/filesystem/fstream.hpp>
namespace newfs=boost::filesystem;
int main()
{
path p("d:/boost/readme.txt");
newfs::ifstream ifs(p.string().c_str());
assert(ifs.is_open());
cout<<ifs.rdbuf();
}
---------------------------------------------------------------------------------------------------------------------------------------------实例一之文件查找
#include<string>
#include<boost/filesystem.hpp>
#include<boost/optional.hpp>
using namespace std;
using namespace boost::filesystem;
using namespace boost;
optional<path> find_file(const path& dir, const string&filename)
{
typedef optional<path> result_type;
if (!exists(dir) || !is_directory(dir))
return result_type();
recursive_directory_iterator end;
for (recursive_directory_iterator pos(dir); pos != end; ++pos)
{
if (!is_directory(*pos) && pos->path().filename() == filename)
return result_type(pos->path());
}
return result_type();
}
void main()
{
optional<path> r = find_file("G:\\TEST", "1122.txt");
if (r)
cout << *r << endl;
else
cout << "file not found" << endl;
}
---------------------------------------------------------------------------------------------------------------------------------------实例二文件名的模糊查询
void find_files(const path& dir, const string&filename,vector<path>v)
{
static xpressive::sregex_compiler rc;//正则表达式工厂
if (!rc[filename].regex_id())
{
string str = replace_all_copy(replace_all_copy(filename, ".", "\\."), "*", ".*");//处理文件名
rc[filename] = rc.compile(str);//创建正则表达式
}
typedef vector<path> result_type;
if (!exists(dir) || !is_directory(dir))
{
return ;
}
recursive_directory_iterator end;
for (recursive_directory_iterator pos(dir); pos != end; ++pos)
{
if (!is_directory(*pos) && regex_match(pos->path().filename(), rc[filename]))
{
v.push_back(pos->path());
}
}
}
-------------------------------------------------------------------------------------------------------------------------------------实例三目录拷贝
size_t copy_files(const path& from_dir, const path& to_dir, const string& filename = "*")
{
if (!is_directory(from_dir))
{
cout << "args is not a dir" << endl;
return 0;
}
cout << "prepare for copy,please wait......" << endl;
vector<path>v;
find_files(from_dir, filename, v);
if (v.empty())
{
cout << "0 file copied" << endl;
return 0;
}
cout << "now begin copy files......" << endl;
path tmp;
progress_display pd(v.size());
BOOST_FOREACH(path& p, v)//for_each 算法
{
tmp = to_dir / p.string().substr(from_dir.string().length());
if (!exists(tmp.parent_path()))
create_directories(tmp.parent_path());
copy_file(p, tmp);
++pd;
cout << v.size() << "file copied" << endl;
return v.size();
}
}
*/