boost filesystem library能使c++程序员写出与操作系统平台无关的操作文件或者目录的代码,本文就是与此相关的。
首先看一下传统的用来操作文件的cpp代码:
#include <iostream> #include <sys/stat.h> #include <errno.h> 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<boost/filesystem/operations.hpp> #include<iostream> namespace bf=boost::filesystem; //标记一 int main(){ bf::path p("first.cpp"); if(bf::exists(p)) std::cout<<p.leaf()<<"exists./n"; else std::cout<<p.leaf()<<"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<boost/filesystem/operations.hpp> #include<iostream> namespace bf=boost::filesystem; int main(){ bf::path p(second.cpp); if(!bf::exists(p)){ std::cout<<p.leaf()<<"doesn't exists./n"; return -1 } if(bf::is_directory(p)) std::cout<<p.leaf()<<"is a directory./n"; else if(bf::symbolic_link_exists(p)) std::cout<<p.leaf()<<"is a symbolic link./n"; else std::cout<<p.leaf()<<"is a regular file./n"; std::cout<<"file size:"<<bf::file_size(p)<<std::endl; std::cout<<"last modification time:"<<bf::last_write_time(p); std::cout<<std::endl; }
下面是boost::filesystem库的一些例子,为了简便,把每个例子需要的头文件放在了一起,如下所示:
#include<boost/filesystem/operations.hpp> #include<iostream> #include<string> 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."<<std::endl;
在上面的代码中,使用了四个库函数:
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."<<std::endl;
或者使用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."<<std::endl; exit(-1); } bfs::directory_iterator dir_iter(p),dir_end; for(;dir_iter!=dir_end;++dir_iter){ std::cout<<"Removing file:"<<dir_iter->leaf(); bfs::remove(*dir_iter); } std::cout<<"Operation COmpleted."<<std::endl;
一个搜寻某个具体文件的函数:
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:"<<p.native_file_string()<<"/n"; else if(!bfs::is_directory(p)) std::cout<<"/nFound:"<<p.native_file_string()<<"/n"; std::cout<<"In Directory:"<<p.native_file_string()<<"/n"; bfs::directory_iterator iter(p),end_iter; for(;iter!=end_iter;++iter){ try{ if(bfs::is_directory(*iter)){ ++dc; std::cout<<iter->leaf()<<"[Directory]/n"; } else{ ++fc; std::cout<<iter->leaf()<<"/n"; } }catch(const std::exception &ex){ std::cout<<iter->leaf()<<":"<<ex.what()<<std::endl; } std::cout<<fc<<" "<<dc<<std::endl; } }
上面的代码,目录名后面加上了[Directory]标签,在代码的最后会显示出要显示的目录下的文件数和目录数,不过上面的代码没有考 虑子目录的情况,上面只打印了文件的native_file_string()属性,还有 is_symbolic_link(),file_size(),last_write_time()等属性。