C++之路(1)filesystem
从C++17标准开始,C++新增加了<filesystem>
标准库,用来处理系统文件。
#include <filesystem>
一、常用类
path
类:该类只对字符串(路径)进行处理,是文件系统的基石。file_status
类:文件(或目录)属性(枚举类)。directory_entry
类:文件、文件夹(目录)。用path
对象构造,构造前应提前判断exists(path)
确保存在。directory_iterator
类:本级目录中的各文件(用于遍历目录)迭代器的容器,其元素为directory_entry
对象。使用path
对象构造,构造前应提前判断path
是目录(file_type::directory
)。recursive_directory_iterator
类:目录及其子目录中的各文件(用于遍历)迭代器的容器。
范例:
#include <filesystem>
using namespace std;
using namespace std::filesystem;
int main(){
path pth("C:\\Windows"); // 构造path对象
if (!exists(pth)) // 必须先检测目录是否存在,才能使用文件入口
return 1;
directory_entry entry(pth); //构造文件入口
if (entry.status().type() == file_type::directory) {/*...*/} // 判断是否为目录。
directory_iterator list(pth); // 目录下所有文件的容器,path对象需要是目录。
for (auto& it:list) { path p = it.path().filename() } //通过it获取path对象的文件名
system("pause");
return 0;
}
二、详细介绍
(一)path
类
只做格式上处理,不做实质性判断,路径可能有误或不存在!
path
对象可以直接用 /
连接:path = path / "newfile"
path
对象用string
构造,并可隐性转化为string
。
1. 拆分
只做字面拆分。返回的仍然是path
对象。
-
root_path()
Linux系统为"/
";windows系统为"C:\
"。等于root_name()
+root_directory()
注意:可能不指定,不存在!root_name()
Linux系统为空;windows系统为"C:
"。注意:可能不指定,不存在。root_directory()
Linux系统为"/
";windows系统为"\
"。注意可能不存在。
-
relative_path()
除了root_path()
之外(后)的。 -
filename()
最后一个/
后边的全部;如果结尾是/
,为空;如果path
根本没有/
,全部。特别注意:.
和..
是filename,只不过有特殊含义。 -
stem()
不包括扩展名的文件名,filename()
最后一个.
(不含)之前的(即使还有.
)。注意:如.
在开头,作为stem的一部分。 -
extension()
扩展名,即filename()
最后一个.
(含)和其后的。 -
parent_path()
最后一个/
(不含)之前的。即对于文件,所在目录;对于目录,上级目录。如果没有上级(或不知道上级),就为本身。
此外:
std::filesystem::current_path()
当前所在目录。(不给参数返回当前;给path
参数修改切换)- 注意:文件处理时,时刻记得以当前目录为立足点,记得切换!
std::filesystem::temp_directory_path()
返回当前系统的TMP文件夹
注意: 这两个系统函数返回的path
都以目录名收尾,不以 /
收尾。(自行构造时string收尾用 /
代表是目录)
2. 判断
返回bool
path.empty()
path.is_absolute()
检查root_path()
,为空为false
。path.is_relative()
等于is_absolute()
取反。path.has_filename()
判断filename()
是否为空,path.has_???()
等其他的同理。
3. 规整规整
返回的仍然是path对象。
absolute(path)
返回绝对路径。如path
本身是绝对路径,原封不动;如不是,等于字面上current_path() + '/' + path
,不做任何解析。如果path
为../abc
,结果为/current/path/../abc
weakly_canonical(path)
返回规范的绝对路径,如果path
为相对路径,则基于current_path()
解析推导。例如path
为../abc
,结果为/current/abc
,注意这个地址可能不存在!如果path不规范、有歧义,则保留歧义,例如path
如为fff/abc
,absolute(path)
为/current/path/fff/abc
,而weakly_canonical(path)
为fff/abc
,不基于current_path()
。canonical(path)
返回规范的绝对路径,并检查地址存不存在!如果地址不存在,抛出异常filesystem_error
。
(二)path定位的系统文件(或目录)属性
1. 取属性:
space(path)
返回地址的空间filesystem::space_info
。其中:(单位均为bytes)space_info.capacity
总容量space_info.free
空闲容量space_info.available
可用容量(小于等于空闲容量)
file_size(path)
返回文件大小,单位bytesstatus(path)
返回filesystem::file_status
。包括两项:file_status.type
返回filesystem::file_type
枚举类
enum class file_type { none, not_found, regular, directory, symlink, unknown };
// 有错、不存在、普通文件、目录、软连接、文件存在但不知道是啥file_status.permissions
返回filesystem::perms
枚举类
enum class perms { none, all, owner_read, ……};
// 0没设、0777(owner_all | group_all | others_all)、0400(作者只读)、……- 可赋值修改!(赋值时返回void)
enum class perms {
none, // 0 no permission bits are set
owner_read, // 0400 File owner has read permission
owner_write, // 0200 File owner has write permission
owner_exec, // 0100 File owner has execute/search permission
owner_all, // 0700 Equivalent to owner_read | owner_write | owner_exec
group_read, group_write, group_exec, group_all, // 040,020,010,070 The file's user group
others_read, others_write, others_exec, others_all, // 04,02,01,07 Other users
all, // 0777 All users. Equivalent to owner_all | group_all | others_all.
mask, // 07777 All valid permission bits.
}
2. 修改权限:
void permissions(path, perms, std::filesystem::perm_options)
其中perm_options
:
enum class perm_options {
replace, // 默认:completely replaced
add, // bitwise OR of the argument to the current permissions
remove, // bitwise AND of the negated argument to the current permissions
nofollow // permissions will be changed on the symlink itself, rather than on the file it resolves to.
};
3. 判断:(返回bool)
status_known(file_status s)
相当于s.type() != file_type::none
exists(s)
相当于status_known(s) && s.type() != file_type::not_found
exists(path)
相当于exists(status(path))
,该版本新建status
对象,效率低,尽量用file_status
版。is_directory(s/path)
两版本,相当于s.type() == file_type::directory
。 注意:以不以/
收尾均可准确判断。is_regular_file(s/path)
is_empty(path)
是否为空文件或空目录
(三)系统文件(或目录)处理
1. 拷贝
void copy(from_path, to_path, copy_options)
拷贝文件或者目录。出错抛出异常。
(默认行为:1重名抛异常;2拷贝目录只拷贝一层的文件,不包括子目录内容;3软链接拷贝其具体指向的文件;4内容拷贝。)
enum class copy_options {
none, # 默认的行为。
skip_existing,
overwrite_existing,
update_existing, # 只有当from的新时,才overwrtie
recursive, # 拷贝子目录及其内容
copy_symlinks, # 软链接也拷贝成软链接
skip_symlinks, # 跳过软链接,不拷贝
directories_only, # 只拷贝目录结构,不拷贝任何非目录文件
create_symlinks,
create_hard_links
};
// 例如:
const auto co1 = std::filesystem::copy_options::recursive; // 修改一项默认行为
const auto co2 = update_existing | recursive | directories_only; // 修改多项默认行为
bool copy_file(from_path, to_path, copy_options)
拷贝单一文件,返回bool,不抛异常。
2. 移动
-
void rename(old_path, new_path)
移动一个文件或者目录!(重命名只是原地移动的场景)。
注意事项:(1)不能省略new_path
目标的名字!(2)new_path
是不存在的文件夹时,不能用/
结尾!(3)new_path
的filename
不能是.
或..
!(4)old_path
是文件夹时,不能是new_path
的上级目录!old_path
不是文件夹,即移动文件时:new_path
不是文件夹,且已存在:删除new_path
,再移动过来。new_path
不存在,但parent_path
存在:移动过来。
old_path
是文件夹,即移动文件夹时:new_path
是文件夹,且已存在:文件夹空时,删除(不空删除会报错!),再移动过来。new_path
不存在,且parent_path
存在,且必须不以/
收尾:移动。
3. 新建
bool create_directory(path)
创建新目录。parent directory必须存在,否则抛异常。如果path已经存在,返回false,不抛异常。bool create_directories(path)
创建新目录。parent directory不用存在,一路新建。如果path已经存在,返回false,不抛异常。
4. 删除
bool remove(path)
删除一个文件或者空目录。path
不存在,返回false
。int remove_all(path)
删除一个文件或者一个目录及目录内全部内容,返回共删除的数量;path
不存在,返回0
。
(三)遍历
1. directory_entry
类(是迭代器的元素)
directory_entry
对象用path
构造,并可隐性转化为path
。
成员函数:path()
成员函数判断:exists
;is_directory
;is_regular_file
;file_size
等。
2. directory_iterator
类
遍历本级目录中的各文件的迭代器,其元素为directory_entry
对象。遍历顺序未知,自动跳过 .
和 ..
文件。
使用 path
对象构造,注意需提前判断 path
是目录(file_type::directory
)。
directory_iterator(path)
directory_iterator(path, std::filesystem::directory_options options)
其中 option:
enum class directory_options {
none, // 默认:Skip directory symlinks, permission denied is error.
follow_directory_symlink, // Follow rather than skip directory symlinks.
skip_permission_denied // Skip directories that would otherwise result in permission denied errors.
};
使用:
for( auto& p : directory_iterator(path) ) {}
2. ecursive_directory_iterator
类
遍历目录及其子目录中的各文件的迭代器。
与 directory_iterator
类 同理 。此外:
int depth()
迭代当前指向的文件夹的深度。起始文件夹为0,其子文件夹为1,以此类推。如果*this
是end
,结果未知!bool recursion_pending()
如果下一个++
还在本级目录中,返回true;如果下一个++
进入子目录,返回false。
最后修改于 2024-02-24