Boost库学习(6)filesystem

C++中标准中,只提供了对特定文件的读写操作方法,而没有定义对于文件路径的操作方法,而在编写代码时,经常中要对文件路径进行处理的(文件是否存在,复制、遍历文件目录等)。如果是GUI程序,可以用QT一类的UI库提供的文件路径相关功能,只是一个命令行程序的话,就比较麻烦了。所以这一篇就来介绍Boost的filesystem库。
Boost的filesystem库主要包括了一些文件操作函数(复制、删除、读取文件属性等),一个path类(用于各种文件路径的变换),两个iterator(用于遍历目录)。

遍历文件目录

<!-- lang: cpp -->
#include <boost/filesystem.hpp>
namespace bfs=boost::filesystem;
template<typename WalkAction>  // 对目录中每一个文件和子目录的处理函数
bool walk(const bfs::path& inpath, WalkAction action, bool recursive)
{
    /* 判断传入的路径是不是一个有效的目录 */
    if (bfs::is_directory(inpath))
    {
        /* 是否遍历子目录 */
        if (recursive)
        {
            for(auto entry=bfs::recursive_directory_iterator(inpath);
                entry!=bfs::recursive_directory_iterator();++entry)
            {
                /* 遍历子目录,并对每一个文件和子目录调用action函数 */
                action(entry->path());
            }
        }
        else
        {
            for(auto entry=bfs::directory_iterator(inpath);
                entry!=bfs::directory_iterator();++entry)
            {
                /* 对当前目录下的每一个文件和子目录调用action函数 */
                action(entry->path());
            }
        }
        return true;
    }
    else
    {
        return false;
    }
}

新建目录

Boost的filesystem库本身是提供了新建目录的函数的,不过有一个不方便的地方,就是只能建一层目录,即要新建”/home/user/abc/def"的话,“/home/usre/abc"目录必须存在,所以我这里把filesystem的函数小小的封闭了一下。

<!-- lang: cpp -->
void makedirs(const bfs::path& inpath)
{
    /* 将传入路径转换成绝对路径 */
    /* absolute()以外还有一个canonical()函数也是取绝对路径 */
    /* canonical()会去掉路径中的".."和".",但是传入参数必须是一个真实有效的路径 */
    bfs::path fpath=bfs::absolute(inpath);
    /* 检查要生成的路径是否已经存在 */
    if (!bfs::is_directory(inpath))
    {
        bfs::path cur;
        /* 如果fpath为"/home/user/abc/def",则fpath.begin()为"/home",fpath.begin()+1为"user" */
        for(auto item=fpath.begin();item!=fpath.end();++item)
        {
            /* 连接路径 */
            cur/=*item;
            if(bfs::is_directory(cur))
            {
                cur=bfs::canonical(cur);
            }
            else
            {
                /* 新建目录 */
                bfs::create_directory(cur);
            }
        }
    }
}

在路径列表中查找指定文件

有时候需要检查某个软件是否已经安装了,而检测的最简单的方法就是看该软件的可执行文件是否存在。比如要检查JDK,只要看有没有javac就行了,至于到底是某公司还是社区提供的JDK其实并不重要。到哪里去找javac呢?因为安装路径可以任意指定,所以一般是在环境变量PATH指定的路径中去查找。

<!-- lang: cpp -->
void findInPath(const std::string& filename, std::initializer_list<std::string> additions, std::vector<bfs::path>& result, int count)
{
    /* 取得环境变量PATH的值 */
    std::string env(std::getenv("PATH"));
#ifdef WIN32
    const std::string sep(";");
#else
    const std::string sep(":");
#endif
    std::string::size_type pos1(0),pos2;
    std::vector<std::string> pathlist;
    /* 优先查找指定目录,所以先把传入的路径加到列表里 */
    pathlist.reserve(additions.size());
    std::copy(additions.begin(),additions.end(),std::back_inserter(pathlist));
    /* 分解环境变量PATH,并将路径加到列表里 */
    while(true)
    {
        pos2=env.find(sep,pos1);
        if (std::string::npos==pos2)
        {
            if (env.size()-pos1>0)
            {
                pathlist.push_back(env.substr(pos1));
            }
            break;
        }
        else
        {
            if (pos2-pos1>0)
            {
                pathlist.push_back(env.substr(pos1,pos2-pos1));
            }
            pos1=pos2+1;
        }
    }
    /* 输出查找目录列表 */
    std::copy(pathlist.cbegin(),pathlist.cend(),
            std::ostream_iterator<std::string>(std::cout,"\n"));
    /* 在列表中的每一个目录中查找目标文件 */
    for (auto &item:pathlist)
    {
        walk(bfs::path(item),
            /* _saveToList函数将查找到的文件存入result中 */
            std::bind(_saveToList,std::placeholders::_1,std::ref(result),filename),
            false);
        if ((count>0) && (result.size()-count>=0))
        {
            break;
        }
    }
}
static void _saveToList(const bfs::path& file,std::vector<bfs::path>& vec,const std::string& filename)
{
    if (file.filename().generic_string()==filename)
    {
        vec.push_back(file);
    }
}

创建一个临时文件

<!-- lang: cpp -->
/* 为临时文件新建一个目录 */
bfs::path tmpfile("temp/abc/def");
makedirs(tmpfile);
/* 生成一个唯一的文件名 */
tmpfile/=bfs::unique_path();
/* 写文件 */
std::ofstream ofs(tmpfile.generic_string());
ofs<<"test\n";
ofs.close();
/* 删除整个临时目录 */
bfs::remove_all("temp");
/* 其它文件操作:
 * copy, copy_directory, copy_file, copy_symlink
 *   copy会自动选择copy_directory/copy_file/copy_symlink中的一个
 * remove, remove_all
 *   remove用来删文件,remove_all用于删目录
 * rename
 */

完整的代码在demo-filesystem目录。

你可能感兴趣的:(C++,boost)