boost-filesystem-删除复制文件-设置文件权限-递归创建删除复制文件夹-解析文件名-C++

文章目录

1.简介

boost::filesystem是Boost C++ Libraries中的一个模块,主要作用是处理文件(Files)和目录(Directories)。该模块提供的类boost::filesystem::path专门用来处理路径。而且,该模块中还有很多独立的函数能够用来执行创建目录、检查文件是否存在等任务。

涉及头文件

cpp 复制代码
// filesystem
#include <boost/filesystem.hpp>
using namespace boost::filesystem;

2.路径合法性

检查路径字符串的合法性。

cpp 复制代码
// path 仅仅是用于表示路径,而并不关心路径中的文件或目录是否存在,路径也可能是个在当前文件系统中无效的名字,例如在Windows 下不允许文件名或目录名使用冒号、尖括号、星号、问号,等等,但path 并不禁止这种表示
path p("/::/*/?/<>"); 
// 完全合法
// -----------------------------------------------------------------------------------------

// 为了提高程序在不同文件系统上的可移植性,filesystem库提供了一系列的文件名(或目录名)检查函数,可以根据系统的命名规则判断一个文件名字符串的有效性,从而尽可能地为程序员编写可移植的程序创造便利。

// portable_posix_name()  检测文件名字符串是否符合POSIX规范(包括大小写字母、点号、下画线和连字符)
// windows_name()         检测文件名字符串是否符合Windows规范(范围要广一些,仅不允许<>?:|/\等少量字符)

// portable_name()        相当于 portable_posix_name()&&windows_name()
//					      但名字不能以点号或者连字符开头,并允许表示当前目录的"."和父目录的".."

// portable_directory_name 包含了portable_name(),名字中不能出现点号,目录名可以移植到OpenVMS操作系统上

// portable_file_name    类似portable_directory_name()
// 						 提供更可移植的文件名,它要求文件名中最多有一个点号,且后缀名不能超过3个字符.


cout << "protable_posix_name, posix:" << portable_posix_name("w+abc.xxx") 
    << "; windows" << windows_name("w+abc.xxx") << endl;

cout << "portable_name:" << portable_name("w+()abc.txt") << "; " 
     << portable_name("./abc") << endl;

cout << "portable_directory_name:" << portable_directory_name("a.txt") << "; "
     << portable_directory_name("abc") << endl;

cout << "portable_file_name:" << portable_directory_name("a.bc") << "; " 
     << portable_file_name("y.conf") << endl;
/*
	protable_posix_name, posix:0; windows1
	portable_name:0; 0
	portable_directory_name:0; 1
	portable_file_name:0; 0
 */

3.路径处理及迭代器

cpp 复制代码
boost::filesystem::path p("/usr/local/include/xxx.hpp");
// 以字符串的形式返回标准格式的路径
cout << p.string() << endl;                 // /usr/local/include/xxx.hpp

// 父路径、全文件名、不含扩展名的文件名和扩展名
cout << p.parent_path() << endl;            // /usr/local/include/ (返回的是path类型)        
cout << p.stem() << endl;                   // xxx
cout << p.filename() << endl;               // xxx.hpp
cout << p.extension() << endl;              // .hpp

// 判断是否是绝对路径
assert(p.is_absolute());                    // Windows 断言不成立
assert(boost::filesystem::system_complete(p).is_absolute());   // 总是完整路径

// 根的名字、根目录和根路径                        若Windows下 path p("c:/xxx/yyy")
cout << p.root_name() << endl;              // linux 空   windows  c:
cout << p.root_directory() << endl;         // linux /    windows  /
cout << p.root_path() << endl;              // linux /    windows  c:/

// 判断路径是否有文件名或者父路径
assert(!p.has_root_name());
assert( p.has_root_path());
assert( p.has_parent_path());

// 使用成员函数compare()基于字典序并且大小写敏感比较路径字符串
// 提供operator==、operator!=、operator<等操作符
boost::filesystem::path p1("/test/1.cpp");
boost::filesystem::path p2("/TEST/1.cpp");
boost::filesystem::path p3("/abc/1.cpp");

assert(p1 != p2);
assert(p2 < p3);

// 迭代器
path p = "/boost/tools/libs";
BOOST_FOREACH(auto& x, p) {              // 使用foreach 算法,也可以用for
	cout << "["<< x << "]";              // 输出路径字符串
}
/*
	[/][boost][tools][libs]
*/

4.设置权限

只读文件,需要去除只读属性,才能进行编辑或者删除。

cpp 复制代码
boost::filesystem::permissions(xmlFilename,boost::filesystem::add_perms | boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write);//设置属性非只读
boost::filesystem::remove(xmlFilename);//删除文件

5.文件操作

filesystem库基于path的路径表示提供了基本的文件操作函数,如创建目录(create_directory)、文件改名(rename)、文件删除(remove)、文件拷贝(copy_file)、创建符号链接(create_symlink),等等,这些函数的名字都很容易理解。

cpp 复制代码
namespace fs = boost::filesystem;                        // 名字空间别名
boost::filesystem::path ptest = "./test";
if (exists(ptest)) {                                     // 检查路径是否存在
    if (boost::filesystem::is_empty(ptest)) {                           // 注意名字空间限定
        boost::filesystem::remove(ptest);                                   // remove只能删除空目录或文件
    }
    else {
        boost::filesystem::remove_all(ptest);                               // remove_all 可以递归删除
    }
}

assert(!boost::filesystem::exists(ptest));                                  // 该目录已经被删除
boost::filesystem::create_directory(ptest);                                 // 创建一个目录

boost::filesystem::copy_file("/usr/local/include/boost/version.hpp", ptest / "a.txt");
assert(boost::filesystem::exists(ptest / "a.txt"));
boost::filesystem::copy_directory("E:\\VSCode","D:\\VSCode"); //复制目录,可以使用copy_directory(),使用时需要注意如果目录已经存在,该函数会失败;

boost::filesystem::rename(ptest / "a.txt", ptest / "b.txt");                // 改名
assert(boost::filesystem::exists(ptest / "b.txt"));

// 使用create_directories 可以一次创建多级目录
boost::filesystem::create_directories(ptest / "sub_dir1" / "sub_dir2");

// 注意
// cpp标准的type_traits库中有一个同名的元函数is_empty,所以我们在这段代码中为is_empty()函数加上了名字空间限定,避免名字冲突。

6.迭代目录

filesystem库提供了迭代一个目录下的所有文件的功能的类:

directory_iterator,基于boost.iterator库的iterator_facade。

recursive_directory_iterator,递归遍历文件系统目录。

6.1. directory_iterator

6.1.1.类摘要
cpp 复制代码
// directory_iterator只能迭代本层目录,不支持深度遍历目录
class directory_iterator : public boost::iterator_facade<
                                directory_iterator,
                                directory_entry,                  // 解引用返回类型
                                boost::single_pass_traversal_tag >
{
public:
    directory_iterator(){}
    directory_iterator(const directory_iterator&);
    explicit directory_iterator(const path& p);
    
    ~directory_iterator();

    directory_iterator& operator=(const directory_iterator&);
    directory_iterator& operator++();
};

// 注意:directory_iterator迭代器返回的对象并不是path,而是一个directory_entry对象
class directory_entry
{
public:
    const path& path() const;                                      // 返回path 对象
    
    file_status status() const;                                    // 获取文件状态
    file_status symlink_status() const;
};
6.1.2.单层目录迭代

directory_iterator只能迭代本层目录,不支持深度遍历目录。

cpp 复制代码
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

void test() {
	// directory_iterator,空的构造函数生成一个逾尾end迭代器,传入path对象构造将开始一个迭代操作,
	// 反复调用operator++即可遍历目录下的所有文件。
	namespace fs = boost::filesystem;
	fs::directory_iterator end;
	for (fs::directory_iterator pos("C:/Users/ajz/Desktop/说明书模板"); pos != end; ++pos) {
		std::cout << *pos << std::endl;
	}

	// 定义一个std::pair区间,使用foreach算法简化迭代
	// 定义一个迭代器的区间
	typedef std::pair<fs::directory_iterator, fs::directory_iterator> dir_range;
	dir_range dr(fs::directory_iterator("C:/Users/ajz/Desktop/说明书模板"),                      // 迭代起点
		fs::directory_iterator());                                      // 迭代终点

	BOOST_FOREACH(auto & x, dr) {                                             // 迭代区间
		std::cout << x << std::endl;
	}
}
6.1.3.directory_iterator深度遍历目录(递归)
cpp 复制代码
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

void recursive_dir(const boost::filesystem::path& dir)                         // 递归遍历目录
{
	boost::filesystem::directory_iterator end;                                 // 结束迭代器调用
	for (boost::filesystem::directory_iterator pos(dir); pos != end; ++pos) {
		if (is_directory(*pos)) {
			recursive_dir(*pos);                            // 是目录则递归遍历
		}
		else {
			std::cout << *pos << std::endl;                           // 不是目录则输出路径
		}
	}
}

//调用
recursive_dir(boost::filesystem::path("C:/Users/ajz/Desktop/说明书模板"));

6.2.recursive_directory_iterator

6.2.1. 类摘要
cpp 复制代码
class recursive_directory_iterator                         // 省略构造、析构函数以及迭代器通用操作
{
public:
    int level() const;                                    // 目录深度
    void pop();                                           // 退出当前目录的遍历
    void no_push();                                       // 不遍历本目录
private:
    int m_level;                                          // 目录深度成员变量
};
/*
	成员函数level()返回当前的目录深度m_level,当rd_iterator构造时(未开始遍历)m_level==0,每深入一层子目录则m_level增加,退出时减少。
	成员函数pop()用于退出当前目录层次的遍历,同时--m_level。
	当迭代到一个目录时,no_push()可以让目录不参与遍历,使rd_iterator的行为等价于directory_iterator。
*/
6.2.2 示例代码
cpp 复制代码
void test() {
	//深度迭代代码,展示文件夹和文件
	rd_iterator end;
	for (rd_iterator pos("C:/Users/ajz/Desktop/说明书模板"); pos != end; ++pos) {
		std::cout << "level" << pos.level() << ":" << *pos << std::endl;
	}

	// 下面的代码使用no_push()令rd_iterator的行为等价于directory_iterator:
	//rd_iterator end;
	for (rd_iterator pos("C:/Users/ajz/Desktop/说明书模板"); pos != end; ++pos) {
		if (is_directory(*pos)) {
			pos.no_push();                                 // 使用no_push(),不深度遍历
		}
		std::cout << *pos << std::endl;
	}
}

7.查找文件、模糊查找文件、复制文件

optional库使用"容器"语义,包装了"可能产生无效值"的对象,实现了"未初始化"的概念。

7.1.查找文件

cpp 复制代码
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <list>

typedef boost::filesystem::recursive_directory_iterator rd_iterator;

boost::optional<std::list<boost::filesystem::path>> FindFile(boost::filesystem::path dir, std::string filename)
{
	// 返回值类型定义
	typedef boost::optional<std::list<boost::filesystem::path>> result_type;

	// 检查目录的有效性
	if (!boost::filesystem::exists(dir) || !boost::filesystem::is_directory(dir)) {
		return result_type();
	}

	// 递归迭代器
	rd_iterator end;
	std::list<boost::filesystem::path> lstPath = std::list<boost::filesystem::path>();
	for (rd_iterator pos(dir); pos != end; ++pos) {
		// 不是目录、文件名相等
		if ((!is_directory(*pos)) && (pos->path().filename() == filename)) {
			lstPath.push_back(pos->path());
		}
	}

	return result_type(lstPath);
}

int main(int argc, char* argv[])
{
	boost::optional<std::list<boost::filesystem::path>> r=FindFile(boost::filesystem::path("C:/Users/ajz/Desktop/说明书模板"),"说明书变量部分.png");
	std::list<boost::filesystem::path> lstPath = r.value();

	// 不存在提示并return
	if (lstPath.size() == 0) {
		std::cout << "file not found." << std::endl;
		return -1;
	}

	for (boost::filesystem::path p : lstPath) {
		std::cout << p << std::endl;
	}
	
	return 0;
}

7.2.正则表达式模糊文件查找

cpp 复制代码
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/xpressive/xpressive_dynamic.hpp>
#include <iostream>
#include <list>

typedef boost::filesystem::recursive_directory_iterator rd_iterator;
std::vector<boost::filesystem::path> FindFiles(const boost::filesystem::path& dir, const std::string& filename)
{
	boost::xpressive::sregex_compiler rc; // 正则表达式工厂
	if (!rc[filename].regex_id()) {
		std::string str = boost::replace_all_copy(
			boost::replace_all_copy(filename, ".", "\\."),
			"*", ".*"); // 处理文件名
		rc[filename] = rc.compile(str); // 创建正则表达式
	}
	typedef std::vector<boost::filesystem::path> result_type; // 返回值类型定义
	result_type v;
	if (!boost::filesystem::exists(dir) || !boost::filesystem::is_directory(dir)) // 目录检查
	{
		return v;
	}
	rd_iterator end; // 递归迭代器逾尾位置
	for (rd_iterator pos(dir); pos != end; ++pos) {
		if (!is_directory(*pos) && boost::xpressive::regex_match(pos->path().filename().string(), rc[filename])) {
			v.push_back(pos->path()); // 找到,加入vector
		}
	}
	return v; // 返回查找的结果
}

int main()
{

	auto v = FindFiles("C:/Users/ajz/Desktop/说明书模板", "*.txt");
	std::cout << v.size() << std::endl;
	for (boost::filesystem::path& p : v) {
		std::cout << p << std::endl;
	}
	return 0;
}

7.3.拷贝目录

cpp 复制代码
#include <iostream>
#define BOOST_ALLOW_DEPRECATED_HEADERS
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <boost/progress.hpp>
#include <boost/xpressive/xpressive_dynamic.hpp>
#include <iostream>
#include <list>

typedef boost::filesystem::recursive_directory_iterator rd_iterator;
std::vector<boost::filesystem::path> FindFiles(const boost::filesystem::path& dir, const std::string& filename)
{
	boost::xpressive::sregex_compiler rc; // 正则表达式工厂
	if (!rc[filename].regex_id()) {
		std::string str = boost::replace_all_copy(
			boost::replace_all_copy(filename, ".", "\\."),
			"*", ".*"); // 处理文件名
		rc[filename] = rc.compile(str); // 创建正则表达式
	}
	typedef std::vector<boost::filesystem::path> result_type; // 返回值类型定义
	result_type v;
	if (!boost::filesystem::exists(dir) || !boost::filesystem::is_directory(dir)) // 目录检查
	{
		return v;
	}
	rd_iterator end; // 递归迭代器逾尾位置
	for (rd_iterator pos(dir); pos != end; ++pos) {
		if (!is_directory(*pos) && boost::xpressive::regex_match(pos->path().filename().string(), rc[filename])) {
			v.push_back(pos->path()); // 找到,加入vector
		}
	}
	return v; // 返回查找的结果
}

size_t CopyFiles(const boost::filesystem::path& from_dir, const boost::filesystem::path& to_dir, const std::string& filename = "*")
{
	if (!boost::filesystem::is_directory(from_dir)) { // 源必须是个目录
		std::cout << "args is not a dir." << std::endl;
		return 0;
	}

	std::cout << "prepare for copy, please wait..." << std::endl;

	auto v = FindFiles(from_dir, filename); // 查找源的所有文件
	if (v.empty()) { // 空目录则不拷贝
		std::cout << "0 file copied." << std::endl;
		return 0;
	}

	std::cout << "now begin copy files ..." << std::endl;
	boost::filesystem::path tmp;
	boost::progress_display pd(v.size()); // 进度显示

	for (auto& p : v) { // 变量容器
		// 拆分基本路径与目标路径
		tmp = to_dir / p.string().substr(from_dir.string().length());
		if (!boost::filesystem::exists(tmp.parent_path())) { // 创建子目录
			boost::filesystem::create_directories(tmp.parent_path());
		}
		boost::filesystem::copy_file(p, tmp); // 拷贝文件
		++pd; // 更新进度
	}

	std::cout << v.size() << " file copied." << std::endl;
	return v.size(); // 完成拷贝
}

int main()
{
	CopyFiles("C:/Users/ajz/Desktop/说明书模板", "C:/Users/ajz/Desktop/说明书模板1");
	return 0;
}

8.总结

filesystem模块提供了关于文件夹和文件常规操作的绝大部分内容,能够跨平台,接口简单易用。

相关推荐
杨荧15 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰22 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_0126 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj32 分钟前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT34 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。36 分钟前
c++多线程
java·开发语言
-Even-36 分钟前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
小政爱学习!38 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯1 小时前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长