boost--filesystem
前言
从18年就开始接触boost
,但是从来没有细细了解过它的功能,因工作需求,这几天看了下boost
,发现确实很强大,真心为以前的无知感到羞愧,boost
包含的内容太多,数据结构,算法,计时等,如果没有具体的使用需求,很难掌握,所以,先从简单常用的东西开始。
学习boost
的核心价值是为了更好的使用C/C++
,将其作为C/C++
的标准扩展,如果遇到重复性的功能且运行模块是相对独立的,会尽可能选择功能较大的一方作为该功能的落脚点。
win
下编译完全功能版的boost
大约1G
左右,在实际使用时,如果嫌弃它过大,可以进行一定程度的阉割,具体实现方法可以百度下。
一、Filesystem简介
作为boost
开篇,把filesystem
模块的使用记录下,因为该模块的主要功能是处理file
与Directories
,拟补了C/C++
的空缺,也解决了跨平台的壁垒,同时,也是考虑使用相对广泛且该模块相对独立,所以,先入手该模块。
二、功能学习
文件及文件夹的操作,相对来说比较固定,新建、删除、复制,重命名,很符合win
下文件管理器的操作指南,但是这其中存在的很多逻辑判断是比较费心劳神的,下面就针对这几种功能的应用场景做一些记录学习。
2.1新建文件夹
在创建文件/夹时,需要一个路径记录文件/夹的位置,因此,在filesystem
中引入了变量boost::filesystem::path
的概念,其实path
在一定程度上是可以和string
表示路径互换的,只是,path
作用比较单一,只表示路径或者某一个路径下的文件,不容易引起误解。
首先,需要给定一个path
,当然,这个path
可以是文件夹,可以是文件,也可以是一些莫名其妙的东西:
path p("./") //当前文件夹
是不是和std::string
有点类似,在接下来的操作中,就以p
作为示例。
在文件管理器(win)
中新建一个文件夹的操作很简单,只需要用户一步一步进入目标文件夹,然后右键新建
即可,但是用代码,就需要留心了,毕竟人非圣贤,孰能无过
,谁又知道你给的参数是否正确,比如,这个p
,只是一个字符串,程序很难知道它具体表示的是什么意思,如果出现非法操作,很有可能导致程序直接崩溃,所以,在拿到p
后首先需要对其进行判别,判断是否存在,判断他的属性等:
if (exists(p)) {
if (is_regular_file(p))
LOG(INFO) << p << "size is " << file_size(p);
else if (is_directory(p))
LOG(INFO) << p << "is a directory , size is ";
else
LOG(WARNING) << "don't know";
}
else {
LOG(INFO) << p << " do not exist";
create_directory(p);
}
上述只是一个简单的操作说明,重点在于逻辑的判断,通过多个if
(只是不习惯用switch
)的设定以及这几句代码,可以实现一些小功能,但是牵扯到应用场景的不同,会出现不同的组合方式,会在下面介绍。
新建文件夹,主要有两个命令:
boost::filesystem::create_directories(path p);
boost::filesystem::create_directory(path p);
两个命令的主要区别是:create_directories()
可以多层创建,简单来说,若p = "./123/456"
,如果不存在123
,则该指令可以先创建文件夹123
然后再创建文件夹456
,但是,若用create_directory()
命令,在没有123
的前提下创建456
,程序直接崩溃。
2.2 删除文件(夹)
删除文件(夹)也有两条命令:
remove(path p)
remove_all(path p)
主要区别:remove()
只能用来删除一个文件或者文件夹,当提供的文件夹里面还存在其余文件时,该命令可导致程序崩溃。
2.3 重命名与复制
相对来说简单很多,一共3条命令:
rename(old, new);
copy_file(old, new);
copy_directory(old, new);
在这里,有几点需要注意:
- 需要注意重名问题,在
rename
与copy
时,若新名字有重名,程序直接挂掉,这与win
下操作逻辑一样。 copy_file
只能复制文件,用来复制文件夹直接挂掉copy_directory()
只能复制文件夹,但是,不负责复制文件夹中的内容。
三、应用场景
场景1:在进行数据处理时,需要保存下中间过程的变量,而且还要方便查阅;
解决思路:基于系统时间创建一些列的文件夹,并将相应数据保存至对应时刻的文件夹中。以年月日
作为一级目录,以时分秒
作为二级目录,并将数据存储其中。
std::string path_f = "./";
std::string path_s = "";
boost::posix_time::ptime now_data = second_clock::local_time();
auto now_time = now_data.time_of_day();
//git current time as folder names
path_f = path_f + to_string(now_data.date().year()) + “-”
+ to_string(now_data .date().month()) + "-"
+ to_string(now_data .date().day());
path_s = to_string(now_time.hours()) + “-” +
to_string(now_time.minutes()) + "-" +
to_string(now_time.seconds);
path p = path_f + "/" + path_s;
//create directories
create_directories(p);
上述是通过create_directories()
创建的,缺点就是,太智能了,不管有没有目标文件夹都会自己创建,过程不好控制,如果想使用create_directory()
创建文件夹,可参考本文第一个示例即可。
场景2:在创建文件夹时,希望按照0,1,2,3...
顺序命名的方式进行;
解决思路:先遍历目标文件夹内部文件的数量,然后进行+1
操作;同时,也可以根据自己的需求统计其中文件与文件夹的数量:
int count = 0;
for (auto it : directory_iterator(p))
count ++;
场景3:给定路径p
,获取其内部包含的所有文件的名称;
解决思路:一个递归搞定
bool get_files(path p, std::vector<path>& names)
{
if (exists(p)) {
if (is_directory(p)) {
for (auto it : directory_iterator(p)) {
if (is_regular_file(it))
names.push_back(it);
else if (is_directory(it))
get_files(it, names);
}
} else
names.push_back(p);
}
else
return false;
}
std::vector<path> names;
bool result = get_files(p, names);