C++17 filesystem 库 学习笔记
- Filesystem library
- 1、类
- 2、非成员函数
- 2.1、std::filesystem::absolute
- 2.2、std::filesystem::canonical, std::filesystem::weakly_canonical
- 2.3、std::filesystem::relative, std::filesystem::proximate
- 2.4、std::filesystem::copy
- 2.5、std::filesystem::copy_file
- 2.6、std::filesystem::copy_symlink
- 2.7、std::filesystem::create_directory, std::filesystem::create_directories
- 2.8、std::filesystem::create_hard_link
- 2.9、std::filesystem::create_symlink, std::filesystem::create_directory_symlink
- 2.10、std::filesystem::current_path
- 2.11、std::filesystem::exists
- 2.12、std::filesystem::equivalent
- 2.13、std::filesystem::file_size
- 2.14、std::filesystem::hard_link_count
- 2.15、std::filesystem::last_write_time
- 2.16、std::filesystem::permissions
- 2.17、std::filesystem::read_symlink
- 2.18、std::filesystem::remove, std::filesystem::remove_all
- 2.19、std::filesystem::rename
- 2.20、std::filesystem::resize_file
- 2.21、std::filesystem::space
- 2.22、std::filesystem::status, std::filesystem::symlink_status
- 2.23、std::filesystem::temp_directory_path
- 3、文件类型
- 3.1、std::filesystem::is_block_file
- 3.2、std::filesystem::is_character_file
- 3.3、std::filesystem::is_directory
- 3.4、std::filesystem::is_empty
- 3.5、std::filesystem::is_fifo
- 3.6、std::filesystem::is_other
- 3.7、std::filesystem::is_regular_file
- 3.8、std::filesystem::is_socket
- 3.9、std::filesystem::is_symlink
- 3.10、std::filesystem::status_known
Filesystem library
官方文档:https://en.cppreference.com/w/cpp/filesystem
Filesystem 由 boost.filesystem 发展而来,自 C++17 开始引入到 ISO C++ 中,用于操作文件系统及其组件(路径、常规文件及文件夹等)。如果希望在较低版本的 C++ 编译器中使用 filesystem,需要换用 boost。
1、类
- 定义于头文件
<filiesystem>
- 定义于命名空间
std::filesystem
这里面的各类不再一一列举,它们的功能直接通过下面表格里的链接跳转到官方页面即可。
path | 路径 |
filesystem_error | 文件系统错误异常 |
directory_entry | 文件夹 |
directory_iterator | 文件夹内容的迭代器 |
recursive_directory_iterator | 递归式迭代指定路径下的所有文件及文件夹 |
file_status | 文件类型及权限 |
space_info | 文件系统中可用的剩余空间信息 |
file_type | 文件类型 |
perms | 文件系统权限标识符 |
perm_options | 指明权限操作的语义 |
copy_options | 指明复制操作的语义 |
directory_options | 对文件夹内容进行迭代时的选项 |
file_time_type | 文件时间信息 |
2、非成员函数
- 定义于头文件
<filiesystem>
- 定义于命名空间
std::filesystem
absolute | 绝对路径 |
canonical、weakly_canonical | 将相对路径转为绝对路径 |
relative、proximate | 相对路径 |
copy | 复制文件或者文件夹 |
copy_file | 复制文件内容 |
copy_symlink | 复制符号链接 |
create_directory、create_directories | 创建新文件夹 |
create_hard_link | 创建硬链接 |
create_symlink、create_directory_symlink | 创建符号链接 |
current_path | 返回或修改当前工作路径 |
exists | 判断路径是否存在 |
equivalent | 判断两个路径是否相同 |
file_size | 返回文件大小 |
hard_link_count | 返回指定文件的硬链接数量 |
last_write_time | 获取或设置最近一次修改数据的时间 |
permissions | 修改访问权限 |
read_symlink | 获取符号链接的目标 |
remove、remove_all | 删除文件或空文件夹,后者可递归式删除非空文件夹 |
rename | 重命名文件或文件夹 |
resize_file | 改变常规文件的大小 |
space | 确定文件系统中的可用剩余空间 |
status、symlink_status | 确定文件属性;检查符号链接目标 |
temp_directory_path | 返回一个存放临时文件的文件夹 |
2.1、std::filesystem::absolute
定义于
<filesystem>
返回包含 p 在内的绝对路径
path absolute( const std::filesystem::path& p );
path absolute( const std::filesystem::path& p, std::error_code& ec );
异常:
如果内存分配失败,任何未标记为 noexcept 的重载函数都可能引发 std::bad_alloc
;
第一个函数在底层系统 API 错误上抛出 std::filesystem::filesystem_error
,构建时将 p 作为第一个路径参数,将系统错误代码作为错误代码参数。
如果系统 API 调用失败,第二个函数会将 std::error_code& 参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()。
注意:
对 p 不存在的情况,并非异常;
对基于 POSIX 的系统来说,std::filesystem::absolute(p)
等价于 std::filesystem::current_path() / p
;
对 Windows 来说,std::filesystem::absolute
可能是基于 GetFullPathNameW
开发的。
案例:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
std::filesystem::path p = "foo.c";
std::cout << "Current path is " << std::filesystem::current_path() << '\n';
std::cout << "Absolute path for " << p << " is " << fs::absolute(p) << '\n';
}
输出:
Current path is "/tmp/1666297965.0051296"
Absolute path for "foo.c" is "/tmp/1666297965.0051296/foo.c"
2.2、std::filesystem::canonical, std::filesystem::weakly_canonical
定义于
<filesystem>
将 p 转换为规范的绝对路径,这两个函数的差异可以详见后面的案例
path canonical( const std::filesystem::path& p );
path canonical( const std::filesystem::path& p,
std::error_code& ec );
path weakly_canonical( const std::filesystem::path& p );
path weakly_canonical( const std::filesystem::path& p,
std::error_code& ec );
异常:
如果内存分配失败,任何未标记为 noexcept 的重载函数都可能引发 std::bad_alloc
;
不带 ec 的几个函数在底层系统 API 错误上抛出 std::filesystem::filesystem_error
,构建时将 p 作为第一个路径参数,将系统错误代码作为错误代码参数。
如果系统 API 调用失败,另外几个函数会将 std::error_code& 参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()。
案例:
#include <filesystem>
#include <iostream>
int main()
{
/* set up sandbox directories:
a
└── b
├── c1
│ └── d <== current path
└── c2
└── e
*/
auto old = std::filesystem::current_path();
auto tmp = std::filesystem::temp_directory_path();
std::filesystem::current_path(tmp);
auto d1 = tmp / "a/b/c1/d";
auto d2 = tmp / "a/b/c2/e";
std::filesystem::create_directories(d1);
std::filesystem::create_directories(d2);
std::filesystem::current_path(d1);
auto p1 = std::filesystem::path("../../c2/./e");
auto p2 = std::filesystem::path("../no-such-file");
std::cout << "Current path is "
<< std::filesystem::current_path() << '\n'
<< "Canonical path for " << p1 << " is "
<< std::filesystem::canonical(p1) << '\n'
<< "Weakly canonical path for " << p2 << " is "
<< std::filesystem::weakly_canonical(p2) << '\n';
try
{
[[maybe_unused]] auto x_x = std::filesystem::canonical(p2);
// NOT REACHED
}
catch (const std::exception& ex)
{
std::cout << "Canonical path for " << p2 << " threw exception:\n"
<< ex.what() << '\n';
}
// cleanup
std::filesystem::current_path(old);
const auto count = std::filesystem::remove_all(tmp / "a");
std::cout << "Deleted " << count << " files or directories.\n";
}
输出:
Current path is "/tmp/a/b/c1/d"
Canonical path for "../../c2/./e" is "/tmp/a/b/c2/e"
Weakly canonical path for "../no-such-file" is "/tmp/a/b/c1/no-such-file"
Canonical path for "../no-such-file" threw exception:
filesystem error: in canonical: No such file or directory [../no-such-file] [/tmp/a/b/c1/d]
Deleted 6 files or directories.
2.3、std::filesystem::relative, std::filesystem::proximate
定义于
<filesystem>
返回相对路径,具体使用方法见后面的案例
path relative( const std::filesystem::path& p,
std::error_code& ec );
path relative( const std::filesystem::path& p,
const std::filesystem::path& base = std::filesystem::current_path() );
path relative( const std::filesystem::path& p,
const std::filesystem::path& base,
std::error_code& ec );
path proximate( const std::filesystem::path& p,
std::error_code& ec );
path proximate( const std::filesystem::path& p,
const std::filesystem::path& base = std::filesystem::current_path() );
path proximate( const std::filesystem::path& p,
const std::filesystem::path& base,
std::error_code& ec );
异常:
如果内存分配失败,任何未标记为 noexcept 的重载函数都可能引发 std::bad_alloc
;
不带 ec 参数的函数在底层系统 API 错误上抛出 std::filesystem::filesystem_error
,构建时将 p 作为第一个路径参数,将系统错误代码作为错误代码参数。
如果系统 API 调用失败,另外几个函数会将 std::error_code& 参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()。
案例:
#include <filesystem>
#include <iostream>
void show(std::filesystem::path x, std::filesystem::path y)
{
std::cout << "x:\t\t " << x << "\ny:\t\t " << y << '\n'
<< "relative(x, y): "
<< std::filesystem::relative(x, y) << '\n'
<< "proximate(x, y): "
<< std::filesystem::proximate(x, y) << "\n\n";
}
int main()
{
show("/a/b/c", "/a/b");
show("/a/c", "/a/b");
show("c", "/a/b");
show("/a/b", "c");
}
输出:
x: "/a/b/c"
y: "/a/b"
relative(x, y): "c"
proximate(x, y): "c"
x: "/a/c"
y: "/a/b"
relative(x, y): "../c"
proximate(x, y): "../c"
x: "c"
y: "/a/b"
relative(x, y): ""
proximate(x, y): "c"
x: "/a/b"
y: "c"
relative(x, y): ""
proximate(x, y): "/a/b"
2.4、std::filesystem::copy
定义于
<filesystem>
可以以指定复制方案的方式,对文件或者文件夹进行复制
void copy( const std::filesystem::path& from,
const std::filesystem::path& to );
void copy( const std::filesystem::path& from,
const std::filesystem::path& to,
std::error_code& ec );
void copy( const std::filesystem::path& from,
const std::filesystem::path& to,
std::filesystem::copy_options options );
void copy( const std::filesystem::path& from,
const std::filesystem::path& to,
std::filesystem::copy_options options,
std::error_code& ec );
案例:
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
fs::create_directories("sandbox/dir/subdir");
std::ofstream("sandbox/file1.txt").put('a');
fs::copy("sandbox/file1.txt", "sandbox/file2.txt"); // copy file
fs::copy("sandbox/dir", "sandbox/dir2"); // copy directory (non-recursive)
const auto copyOptions = fs::copy_options::update_existing
| fs::copy_options::recursive
| fs::copy_options::directories_only
;
fs::copy("sandbox", "sandbox_copy", copyOptions);
static_cast<void>(std::system("tree"));
fs::remove_all("sandbox");
fs::remove_all("sandbox_copy");
}
输出:
.
├── sandbox
│ ├── dir
│ │ └── subdir
│ ├── dir2
│ ├── file1.txt
│ └── file2.txt
└── sandbox_copy
├── dir
│ └── subdir
└── dir2
8 directories, 2 files
异常的情况与其他函数基本相同,后面不再赘述。
函数在执行时的具体行为
- 首先,在执行任何其他操作之前,只需对下面的两个函数进行一次调用,即可获得
from
的类型和权限:std::filesystem::symlink_status
(如果在 options 中指定了copy_options::skip_symlinks
,copy_options::copy_symlinks
, 或copy_options::create_symlinks
)std::filesystem::status
(其他情况)
- 如果有必要,只需对下面的两个函数进行一次调用,即可获得
to
的状态:std::filesystem::symlink_status
(如果在 options 中指定了copy_options::skip_symlinks
, 或copy_options::create_symlinks
))std::filesystem::status
(包含在 options 中指定copy_options::copy_symlinks
在内的其他情况)
- 如果 from 或 to 中有 implementation-defined 文件类型,则函数的执行效果也是 implementation-defined;
- 如果 from 不存在,函数将报错;
- 如果 from 与 to 是相同的,函数将报错(具体来说,两者是通过函数
std::filesystem::equivalent
判定是否相同的); - 如果 from 或 to 不是常规文件、文件夹或者符号链接,则函数报错(通过函数
std::filesystem::is_other
判定的); - 如果 from 是文件夹,to 是常规文件,则函数报错;
- 如果 from 是符号链接,则有(以下三条,优先级逐渐降低):
- 如果 options 中有
copy_options::skip_symlink
,则函数啥也不干 - 否则,如果 to 不存在,且 options 中有
copy_options::copy_symlinks
,则函数的行为与copy_symlink(from, to)
一致; - 对不含上面情况的其他情形,函数报错;
- 如果 options 中有
- 如果 from 是常规文件,则有(以下五条,优先级逐渐降低):
- 如果设置 options 为
copy_options::directories_only
,则函数啥也不干; - 否则,如果 options 中有
copy_options::create_symlinks
,函数创建一个符号链接(from 必须为绝对路径) - 否则,如果 options 中有
copy_options::create_hard_links
,函数创建一个硬链接 - 否则,如果 to 是文件夹,那函数的行为与
copy_file(from, to/from.filename(), options)
相同(即在 to 中创建一个文件) - 否则,与函数
copy_file(from, to, options)
的表现相同。
- 如果设置 options 为
- 如果 from 是文件夹,并且在 options 中设置了
copy_options::create_symlinks
,函数将会报错,相应的错误代码为std::make_error_code(std::errc::is_a_directory)
; - 如果 from 是文件夹,而 options 中设置了
copy_options::recursive
或copy_options::none
,则:- 如果 to 不存在,函数将先执行
create_directory(to, from)
, - 然后,在 from 中含有的文件中进行迭代(使用了
for (const std::filesystem::directory_entry& x : std::filesystem::directory_iterator(from))
),并在每个子文件夹中递归地调用copy(x.path(), to/x.path().filename(), options | in-recursive-copy)
- 如果 to 不存在,函数将先执行
- 对 from 与 to 的其他情况,函数什么也不做。
2.5、std::filesystem::copy_file
定义于
<filesystem>
可以以指定复制方案的方式,对文件进行复制
bool copy_file( const std::filesystem::path& from,
const std::filesystem::path& to );
bool copy_file( const std::filesystem::path& from,
const std::filesystem::path& to,
std::error_code& ec );
bool copy_file( const std::filesystem::path& from,
const std::filesystem::path& to,
std::filesystem::copy_options options );
bool copy_file( const std::filesystem::path& from,
const std::filesystem::path& to,
std::filesystem::copy_options options,
std::error_code& ec );
案例:
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
fs::create_directory("sandbox");
std::ofstream("sandbox/file1.txt").put('a');
fs::copy_file("sandbox/file1.txt", "sandbox/file2.txt");
// now there are two files in sandbox:
std::cout << "file1.txt holds: "
<< std::ifstream("sandbox/file1.txt").rdbuf() << '\n';
std::cout << "file2.txt holds: "
<< std::ifstream("sandbox/file2.txt").rdbuf() << '\n';
// fail to copy directory
fs::create_directory("sandbox/abc");
try
{
fs::copy_file("sandbox/abc", "sandbox/def");
}
catch (fs::filesystem_error& e)
{
std::cout << "Could not copy sandbox/abc: " << e.what() << '\n';
}
fs::remove_all("sandbox");
}
输出:
file1.txt holds: a
file2.txt holds: a
Could not copy sandbox/abc: copy_file: Is a directory: "sandbox/abc", "sandbox/def"
函数执行时的行为
- 前两个函数相当于在后两个函数中为 options 设置
copy_options::none
; - 后两个函数中,基于 options 中的设置内容,从 from 中复制一份文件到 to 中。如果 options 中的任何copy_options 选项组中存在多个 option,则函数的行为未定义。
- 如果
!filesystem::is_regular_file(from)
为 true,则函数报错; - 否则,如果 to 不存在,
- 复制 from 的内容及属性;
- 否则,如果 to 已经存在了,
- 如果有下面的情况,函数就报错:
- to 与 from 相同(由
filesystem::equivalent(from, to)
判定) - to 不是常规文件(由
! filesystem::is_regular_file(to)
判定) - options 中没有设置控制选项
- to 与 from 相同(由
- 否则,如果在 options 中设置了
copy_options::skip_existing
,则函数什么也不做; - 否则,如果在 options 中设置了
copy_options::overwrite_existing
,执行复制操作,替换掉已有文件; - 否则,如果在 options 中设置了
copy_options::update_existing
,则仅在 from 比 to 较新的时候才会进行复制(用filesystem::last_write_time()
的执行结果判定 from 是否比 to 新)
- 如果有下面的情况,函数就报错:
- 如果
2.6、std::filesystem::copy_symlink
定义于
<filesystem>
可以以指定复制方案的方式,对符号链接进行复制
第一个函数依据 from 是文件还是文件夹,将以
f(read_symlink(from), to)
的形式调用函数create_symlink
或create_directory_symlink
;第二个函数依据 from 是文件还是文件夹,将以
f(read_symlink(from), to, ec)
的形式调用函数create_symlink
或create_directory_symlink
;
void copy_symlink( const std::filesystem::path& from,
const std::filesystem::path& to);
void copy_symlink( const std::filesystem::path& from,
const std::filesystem::path& to,
std::error_code& ec ) noexcept;
2.7、std::filesystem::create_directory, std::filesystem::create_directories
bool create_directory( const std::filesystem::path& p );
bool create_directory( const std::filesystem::path& p, std::error_code& ec ) noexcept;
bool create_directory( const std::filesystem::path& p,
const std::filesystem::path& existing_p );
bool create_directory( const std::filesystem::path& p,
const std::filesystem::path& existing_p,
std::error_code& ec ) noexcept;
bool create_directories( const std::filesystem::path& p );
bool create_directories( const std::filesystem::path& p, std::error_code& ec );
第三和第四个函数不同于另外四个,它俩创建的新文件夹的属性是从 existing_p
中复制来的(仅在 POSIX 系统中是这样的,在 Windows 中并未复制属性值):
stat(existing_p.c_str(), &attributes_stat)
mkdir(p.c_str(), attributes_stat.st_mode)
案例:
#include <cassert>
#include <cstdlib>
#include <filesystem>
int main()
{
std::filesystem::current_path(std::filesystem::temp_directory_path());
// Basic usage
std::filesystem::create_directories("sandbox/1/2/a");
std::filesystem::create_directory("sandbox/1/2/b");
// Directory already exists (false returned, no error)
assert(!std::filesystem::create_directory("sandbox/1/2/b"));
// Permissions copying usage
std::filesystem::permissions(
"sandbox/1/2/b",
std::filesystem::perms::others_all,
std::filesystem::perm_options::remove
);
std::filesystem::create_directory("sandbox/1/2/c", "sandbox/1/2/b");
std::system("ls -l sandbox/1/2");
std::system("tree sandbox");
std::filesystem::remove_all("sandbox");
}
输出:
drwxr-xr-x 2 user group 4096 Apr 15 09:33 a
drwxr-x--- 2 user group 4096 Apr 15 09:33 b
drwxr-x--- 2 user group 4096 Apr 15 09:33 c
sandbox
└── 1
└── 2
├── a
├── b
└── c
2.8、std::filesystem::create_hard_link
void create_hard_link( const std::filesystem::path& target,
const std::filesystem::path& link );
void create_hard_link( const std::filesystem::path& target,
const std::filesystem::path& link,
std::error_code& ec ) noexcept;
该函数将为 target 创建一个硬链接,其中 target 必须设定;
一旦被创建,link 与 target 就成为指向同一个文件的两个逻辑名(它们是等价的),如果 target 被删除,原文件将继续存在,link 也继续指向它。
注意:
一些操作系统不支持硬链接,或者仅在常规文件中支持;
有些操作系统可能支持硬链接,但其中的文件系统可能不支持,例如闪存中的 FAT 文件系统;
一些文件系统对每个文件所能拥有的硬链接的数量进行了限制;
仅管理员具有硬链接到文件夹的权限;
硬链接通常不能跨越文件系统边界。
特殊的路径名 .
是向其父文件夹的一个硬链接,而 ..
是向其父文件夹的父文件夹的一个硬链接。
案例:
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
fs::create_directories("sandbox/subdir");
std::ofstream("sandbox/a").put('a'); // create regular file
fs::create_hard_link("sandbox/a", "sandbox/b");
fs::remove("sandbox/a");
// read from the original file via surviving hard link
char c = std::ifstream("sandbox/b").get();
std::cout << c << '\n';
fs::remove_all("sandbox");
}
输出:
a
2.9、std::filesystem::create_symlink, std::filesystem::create_directory_symlink
void create_symlink( const std::filesystem::path& target,
const std::filesystem::path& link );
void create_symlink( const std::filesystem::path& target,
const std::filesystem::path& link,
std::error_code& ec ) noexcept;
void create_directory_symlink( const std::filesystem::path& target,
const std::filesystem::path& link );
void create_directory_symlink( const std::filesystem::path& target,
const std::filesystem::path& link,
std::error_code& ec ) noexcept;
创建符号链接
注意:
一些操作系统并不支持符号链接,或者仅在常规文件上支持;
有些操作系统可能支持符号链接,但其中的文件系统可能不支持,例如闪存中的 FAT 文件系统;
与硬链接一样,符号链接允许文件同时拥有多个逻辑名,但硬链接要求原文件必须存在,而符号链接可以独立于原文件存在,且能跨越文件系统边界。
案例:
#include <cassert>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
fs::create_directories("sandbox/subdir");
fs::create_symlink("target", "sandbox/sym1");
fs::create_directory_symlink("subdir", "sandbox/sym2");
for (auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
if (is_symlink(it->symlink_status()))
std::cout << *it << "->" << read_symlink(*it) << '\n';
assert(std::filesystem::equivalent("sandbox/sym2", "sandbox/subdir"));
fs::remove_all("sandbox");
}
输出:
"sandbox/sym1"->"target"
"sandbox/sym2"->"subdir"
2.10、std::filesystem::current_path
path current_path();
path current_path( std::error_code& ec );
void current_path( const std::filesystem::path& p );
void current_path( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
返回或者修改当前的工作路径
案例:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
std::cout << "Current path is " << fs::current_path() << '\n'; // (1)
fs::current_path(fs::temp_directory_path()); // (3)
std::cout << "Current path is " << fs::current_path() << '\n';
}
输出:
Current path is "D:/local/ConsoleApplication1"
Current path is "E:/Temp"
2.11、std::filesystem::exists
bool exists( std::filesystem::file_status s ) noexcept;
bool exists( const std::filesystem::path& p );
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept;
检查当前的文件或文件夹是否存在;
第一个函数等价于
status_known(s) && s.type() != file_type::not_found
第二第三个函数中,令 s 为用
status(p)
或status(p, ec)
决定的std::filesystem::file_status
,则这两个函数返回的值为exists(s)
,第三个函数在status_known(s)
为真时,将调用ec.clear()
案例:
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
void demo_exists(const fs::path& p, fs::file_status s = fs::file_status{})
{
std::cout << p;
if (fs::status_known(s) ? fs::exists(s) : fs::exists(p))
std::cout << " exists\n";
else
std::cout << " does not exist\n";
}
int main()
{
const fs::path sandbox{"sandbox"};
fs::create_directory(sandbox);
std::ofstream{sandbox/"file"}; // create regular file
fs::create_symlink("non-existing", sandbox/"symlink");
demo_exists(sandbox);
for (const auto& entry : fs::directory_iterator(sandbox))
demo_exists(entry, entry.status()); // use cached status from directory entry
fs::remove_all(sandbox);
}
输出:
"sandbox" exists
"sandbox/symlink" does not exist
"sandbox/file" exists
2.12、std::filesystem::equivalent
bool equivalent( const std::filesystem::path& p1,
const std::filesystem::path& p2 );
bool equivalent( const std::filesystem::path& p1,
const std::filesystem::path& p2,
std::error_code& ec ) noexcept;
用于检查两个路径是否指向同一个文件系统实体
如果 p1 或者 p2 不存在,函数将报错。
注意:
判定相等的方式:两个路径指向的实体在同一个设备的同一个位置。对 POSIX 来说,在通过 stat()
获得的两个路径的 stat
结构体中,st_dev
与 st_ino
是对应相等的。
另外,同一个文件或文件夹的所有硬链接是等价的,同一个文件系统中的符号链接与其 target 之间是等价的。
案例:
#include <cstdint>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
// hard link equivalency
fs::path p1 = ".";
fs::path p2 = fs::current_path();
if (fs::equivalent(p1, p2))
std::cout << p1 << " is equivalent to " << p2 << '\n';
// symlink equivalency
for (const fs::path lib : {"/lib/libc.so.6", "/lib/x86_64-linux-gnu/libc.so.6"})
{
try
{
p2 = lib.parent_path() / fs::read_symlink(lib);
}
catch (std::filesystem::filesystem_error const& ex)
{
std::cout << ex.what() << '\n';
continue;
}
if (fs::equivalent(lib, p2))
std::cout << lib << " is equivalent to " << p2 << '\n';
}
}
输出:
"." is equivalent to "/var/tmp/test"
filesystem error: read_symlink: No such file or directory [/lib/libc.so.6]
"/lib/x86_64-linux-gnu/libc.so.6" is equivalent to "/lib/x86_64-linux-gnu/libc-2.23.so"
2.13、std::filesystem::file_size
std::uintmax_t file_size( const std::filesystem::path& p );
std::uintmax_t file_size( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
当 p 不存在时,函数报错;
案例:
#include <cmath>
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
struct HumanReadable
{
std::uintmax_t size{};
private:
friend std::ostream& operator<<(std::ostream& os, HumanReadable hr)
{
int o{};
double mantissa = hr.size;
for (; mantissa >= 1024.; mantissa /= 1024., ++o);
os << std::ceil(mantissa * 10.) / 10. << "BKMGTPE"[o];
return o ? os << "B (" << hr.size << ')' : os;
}
};
int main(int, char const* argv[])
{
fs::path example = "example.bin";
fs::path p = fs::current_path() / example;
std::ofstream(p).put('a'); // create file of size 1
std::cout << example << " size = " << fs::file_size(p) << '\n';
fs::remove(p);
p = argv[0];
std::cout << p << " size = " << HumanReadable{fs::file_size(p)} << '\n';
try
{
std::cout << "Attempt to get size of a directory:\n";
[[maybe_unused]] auto x_x = fs::file_size("/dev");
}
catch (fs::filesystem_error& e)
{
std::cout << e.what() << '\n';
}
for (std::error_code ec; fs::path bin : {"cat", "mouse"})
{
bin = "/bin"/bin;
if (const std::uintmax_t size = fs::file_size(bin, ec); ec)
std::cout << bin << " : " << ec.message() << '\n';
else
std::cout << bin << " size = " << HumanReadable{size} << '\n';
}
}
输出:
"example.bin" size = 1
"./a.out" size = 22KB (22512)
Attempt to get size of a directory:
filesystem error: cannot get file size: Is a directory [/dev]
"/bin/cat" size = 50.9KB (52080)
"/bin/mouse" : No such file or directory
2.14、std::filesystem::hard_link_count
std::uintmax_t hard_link_count( const std::filesystem::path& p );
std::uintmax_t hard_link_count( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
返回 p 的硬链接数量
案例:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
// On a POSIX-style filesystem, each directory has at least 2 hard links:
// itself and the special member pathname "."
fs::path p = fs::current_path();
std::cout << "Number of hard links for current path is "
<< fs::hard_link_count(p) << '\n';
// Each ".." is a hard link to the parent directory, so the total number
// of hard links for any directory is 2 plus number of direct subdirectories
p = fs::current_path() / ".."; // Each dot-dot is a hard link to parent
std::cout << "Number of hard links for .. is "
<< fs::hard_link_count(p) << '\n';
}
输出:
Number of hard links for current path is 2
Number of hard links for .. is 3
2.15、std::filesystem::last_write_time
std::filesystem::file_time_type last_write_time( const std::filesystem::path& p );
std::filesystem::file_time_type last_write_time( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
void last_write_time( const std::filesystem::path& p,
std::filesystem::file_time_type new_time );
void last_write_time( const std::filesystem::path& p,
std::filesystem::file_time_type new_time,
std::error_code& ec ) noexcept;
返回最近一次修改的时间
案例:
#include <chrono>
#include <filesystem>
#include <format>
#include <fstream>
#include <iostream>
using namespace std::chrono_literals;
int main()
{
auto p = std::filesystem::temp_directory_path() / "example.bin";
std::ofstream{p.c_str()}.put('a'); // create file
std::filesystem::file_time_type ftime = std::filesystem::last_write_time(p);
std::cout << std::format("File write time is {}\n", ftime);
// move file write time 1 hour to the future
std::filesystem::last_write_time(p, ftime + 1h);
// read back from the filesystem
ftime = std::filesystem::last_write_time(p);
std::cout << std::format("File write time is {}\n", ftime);
std::filesystem::remove(p);
}
输出:
File write time is 2023-09-04 19:33:24.702639224
File write time is 2023-09-04 20:33:24.702639224
2.16、std::filesystem::permissions
void permissions( const std::filesystem::path& p,
std::filesystem::perms prms,
std::filesystem::perm_options opts = perm_options::replace );
void permissions( const std::filesystem::path& p,
std::filesystem::perms prms,
std::error_code& ec ) noexcept;
void permissions( const std::filesystem::path& p,
std::filesystem::perms prms,
std::filesystem::perm_options opts,
std::error_code& ec );
修改文件权限
在设置 prms 与 opts 参数时,有以下效果:
- 如果 opts 为
perm_options::replace
,文件权限将被设为prms & std::filesystem::perms::mask
;- 如果 opts 为
perm_options::add
,文件权限将被设为status(p).permissions() | (prms & perms::mask)
;- 如果 opts 为
perm_options::remove
,文件权限将被设为status(p).permissions() & ~(prms & perms::mask)
opts 仅能被设为 replace、add 与 remove 中的一个。
案例:
#include <filesystem>
#include <fstream>
#include <iostream>
void demo_perms(std::filesystem::perms p)
{
using std::filesystem::perms;
auto show = [=](char op, perms perm)
{
std::cout << (perms::none == (perm & p) ? '-' : op);
};
show('r', perms::owner_read);
show('w', perms::owner_write);
show('x', perms::owner_exec);
show('r', perms::group_read);
show('w', perms::group_write);
show('x', perms::group_exec);
show('r', perms::others_read);
show('w', perms::others_write);
show('x', perms::others_exec);
std::cout << '\n';
}
int main()
{
std::ofstream("test.txt"); // create file
std::cout << "Created file with permissions: ";
demo_perms(std::filesystem::status("test.txt").permissions());
std::filesystem::permissions(
"test.txt",
std::filesystem::perms::owner_all | std::filesystem::perms::group_all,
std::filesystem::perm_options::add
);
std::cout << "After adding u+rwx and g+rwx: ";
demo_perms(std::filesystem::status("test.txt").permissions());
std::filesystem::remove("test.txt");
}
输出:
Created file with permissions: rw-r--r--
After adding u+rwx and g+wrx: rwxrwxr--
2.17、std::filesystem::read_symlink
std::filesystem::path read_symlink( const std::filesystem::path& p );
std::filesystem::path read_symlink( const std::filesystem::path& p,
std::error_code& ec );
返回符号链接指向的目标路径
案例:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
for (fs::path p : {"/usr/bin/gcc", "/bin/cat", "/bin/mouse"})
{
std::cout << p;
fs::exists(p) ?
fs::is_symlink(p) ?
std::cout << " -> " << fs::read_symlink(p) << '\n' :
std::cout << " exists but it is not a symlink\n" :
std::cout << " does not exist\n";
}
}
输出:
"/usr/bin/gcc" -> "gcc-5"
"/bin/cat" exists but it is not a symlink
"/bin/mouse" does not exist
2.18、std::filesystem::remove, std::filesystem::remove_all
bool remove( const std::filesystem::path& p );
bool remove( const std::filesystem::path& p, std::error_code& ec ) noexcept;
std::uintmax_t remove_all( const std::filesystem::path& p );
std::uintmax_t remove_all( const std::filesystem::path& p, std::error_code& ec );
删除文件或者文件夹
第一个函数在处理文件夹时,仅能处理空的;如果想删除文件夹及其所有内容,应该使用第二个函数
注意:
在 POSIX 系统中,相当于在执行 unlink
与 rmdir
在 Windows 中,在执行 DeleteFileW
与 RemoveDirectoryW
案例:
#include <cstdint>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
fs::path tmp{std::filesystem::temp_directory_path()};
std::filesystem::create_directories(tmp / "abcdef/example");
std::uintmax_t n{fs::remove_all(tmp / "abcdef")};
std::cout << "Deleted " << n << " files or directories\n";
}
输出:
Deleted 2 files or directories
2.19、std::filesystem::rename
void rename( const std::filesystem::path& old_p,
const std::filesystem::path& new_p );
void rename( const std::filesystem::path& old_p,
const std::filesystem::path& new_p,
std::error_code& ec ) noexcept;
移动或者依据指定的
old_p
与new_p
对文件系统对象进行重命名。
- 如果
old_p
不是文件夹,那么new_p
就必须为下面几种情况:
- 与
old_p
相同的文件,或者是它的硬链接:函数啥也不干;- 已存在:函数中,首先将
new_p
删除,然后将new_p
链到old_p
所指向的文件,最后将old_p
解连。- 该文件不存在,但文件所在的文件夹存在:函数进行正常的移动操作;
- 如果
old_p
是文件夹,那new_p
为下面中的几种:
- 与
old_p
相同的文件夹,或者是它的硬链接:函数啥也不干;- 已经存在:正常的移动操作,与前面
old_p
是文件的对应情况类似;- 不存在,且不以文件夹分隔符结尾,且其父文件夹存在:与前面的移动操作类似,不再赘述。
- 操作符号链接:rename 改变的只是符号链接的名称,不是目标对象的。如果
new_p
是一个已经存在的符号链接,那在该函数将把它删除。以下三种情况中,函数会执行失败:
new_p
以.
或者..
结尾;new_p
是一个不存在的文件夹,且以文件夹分隔符结尾;
old_p
是一个文件夹,且为new_p
的某个上级目录。
案例:
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
int main()
{
std::filesystem::path p = std::filesystem::current_path() / "sandbox";
std::filesystem::create_directories(p / "from");
std::ofstream{ p / "from/file1.txt" }.put('a');
std::filesystem::create_directory(p / "to");
// fs::rename(p / "from/file1.txt", p / "to/"); // error: "to" is a directory
fs::rename(p / "from/file1.txt", p / "to/file2.txt"); // OK
// fs::rename(p / "from", p / "to"); // error: "to" is not empty
fs::rename(p / "from", p / "to/subdir"); // OK
std::filesystem::remove_all(p);
}
2.20、std::filesystem::resize_file
void resize_file( const std::filesystem::path& p,
std::uintmax_t new_size );
void resize_file( const std::filesystem::path& p,
std::uintmax_t new_size,
std::error_code& ec ) noexcept;
修改常规文件 p 的大小。
如果文件尺寸比新尺寸大,多出来的那部分会被舍弃;
如果文件尺寸比新尺寸小,则文件尺寸将增加,且增加的那部分用 0 填充。
注意:
对支持稀疏文件的系统,增加文件尺寸并不会增加其在文件系统中所占的空间:仅仅在非零数值被写入到文件的时候,其占用的空间才会增加。
案例:
通过在剩余空间中创建稀疏文件来说明
#include <filesystem>
#include <fstream>
#include <iostream>
#include <locale>
int main()
{
auto p = std::filesystem::temp_directory_path() / "example.bin";
std::ofstream{p}.put('a');
std::cout.imbue(std::locale{"en_US.UTF8"});
std::cout << "File size: " << std::filesystem::file_size(p) << '\n'
<< "Free space: " << std::filesystem::space(p).free << '\n';
std::filesystem::resize_file(p, 64*1024); // resize to 64 KB
std::cout << "File size: " << std::filesystem::file_size(p) << '\n'
<< "Free space: " << std::filesystem::space(p).free << '\n';
std::filesystem::remove(p);
}
输出:
File size: 1
Free space: 42,954,108,928
File size: 65,536
Free space: 42,954,108,928
2.21、std::filesystem::space
std::filesystem::space_info space( const std::filesystem::path& p );
std::filesystem::space_info space( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
判定 p 所在文件系统的空间信息。其行为类似于 POSIX 的
statvfs
。返回值类型中,设定值的方式与 POSIX 结构体
statvfs
的对应关系为:
space_info.capacity
将设定为f_blocks * f_frsize
;space_info.free
将设定为f_bfree * f_frsize
;space_info.available
将设定为f_bavail * f_frsize
;- 无法判断的就设为
static_cast<std::uintmax_t>(-1)
注意:
space_info.available
可能比 space_info.free
小。
案例:
#include <cstdint>
#include <filesystem>
#include <iostream>
std::uintmax_t disk_usage_percent(const std::filesystem::space_info& si,
bool is_privileged = false) noexcept
{
if (constexpr std::uintmax_t X(-1);
si.capacity == 0 || si.free == 0 || si.available == 0 ||
si.capacity == X || si.free == X || si.available == X
)
return 100;
std::uintmax_t unused_space = si.free, capacity = si.capacity;
if (!is_privileged)
{
const std::uintmax_t privileged_only_space = si.free - si.available;
unused_space -= privileged_only_space;
capacity -= privileged_only_space;
}
const std::uintmax_t used_space{capacity - unused_space};
return 100 * used_space / capacity;
}
void print_disk_space_info(auto const& dirs, int width = 14)
{
(std::cout << std::left).imbue(std::locale("en_US.UTF-8"));
for (const auto s : {"Capacity", "Free", "Available", "Use%", "Dir"})
std::cout << "│ " << std::setw(width) << s << ' ';
for (std::cout << '\n'; auto const& dir : dirs)
{
std::error_code ec;
const std::filesystem::space_info si = std::filesystem::space(dir, ec);
for (auto x : {si.capacity, si.free, si.available, disk_usage_percent(si)})
std::cout << "│ " << std::setw(width) << static_cast<std::intmax_t>(x) << ' ';
std::cout << "│ " << dir << '\n';
}
}
int main()
{
const auto dirs = {"/dev/null", "/tmp", "/home", "/proc", "/null"};
print_disk_space_info(dirs);
}
输出:
│ Capacity │ Free │ Available │ Use% │ Dir
│ 84,417,331,200 │ 42,732,986,368 │ 40,156,028,928 │ 50 │ /dev/null
│ 84,417,331,200 │ 42,732,986,368 │ 40,156,028,928 │ 50 │ /tmp
│ -1 │ -1 │ -1 │ 100 │ /home
│ 0 │ 0 │ 0 │ 100 │ /proc
│ -1 │ -1 │ -1 │ 100 │ /null
2.22、std::filesystem::status, std::filesystem::symlink_status
std::filesystem::file_status status( const std::filesystem::path& p );
std::filesystem::file_status status( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
std::filesystem::file_status symlink_status( const std::filesystem::path& p );
std::filesystem::file_status symlink_status( const std::filesystem::path& p,
std::error_code& ec ) noexcept;
前两个函数用于确定 p 指定的文件系统对象的类型与属性
- 如果 p 是常规文件,函数返回
file_status(file_type::regular, prms)
;- 如果 p 是文件夹,函数返回
file_status(file_type::directory, prms)
;- 如果 p 是块文件,函数返回
file_status(file_type::block, prms)
;- 如果 p 是字符文件,函数返回
file_status(file_type::character, prms)
;- 如果 p 是 fifo 或 pipo 文件,函数返回
file_status(file_type::fifo, prms)
;- 如果 p 是 socket 文件,函数返回
file_status(file_type::socket, prms)
;- 如果 p 是 implementation-defined 文件类型,函数返回
file_status(file_type::A, prms)
,其中 A 是那种类型的 implementation-defined file_type 常数;- 如果 p 不存在,函数返回
file_status(file_type::not_found)
;- 如果 p 存在,但无法确定文件的属性,函数返回
file_status(file_type::unknown)
;- 如果 p 存在,但出错,函数返回
file_status(file_type::none)
;- 其他情况,函数返回
file_status(file_type::unknown, prms)
;后两个函数与前两个的功能基本相同,但额外多一个功能:
- 如果 p 是符号链接,函数返回
file_status(file_type::symlink)
案例:
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
namespace fs = std::filesystem;
void demo_status(const fs::path& p, fs::file_status s)
{
std::cout << p;
// alternative: switch(s.type()) { case fs::file_type::regular: ...}
if (fs::is_regular_file(s))
std::cout << " is a regular file\n";
if (fs::is_directory(s))
std::cout << " is a directory\n";
if (fs::is_block_file(s))
std::cout << " is a block device\n";
if (fs::is_character_file(s))
std::cout << " is a character device\n";
if (fs::is_fifo(s))
std::cout << " is a named IPC pipe\n";
if (fs::is_socket(s))
std::cout << " is a named IPC socket\n";
if (fs::is_symlink(s))
std::cout << " is a symlink\n";
if (!fs::exists(s))
std::cout << " does not exist\n";
}
int main()
{
// create files of different kinds
fs::create_directory("sandbox");
fs::create_directory("sandbox/dir");
std::ofstream{"sandbox/file"}; // create regular file
fs::create_symlink("file", "sandbox/symlink");
mkfifo("sandbox/pipe", 0644);
sockaddr_un addr;
addr.sun_family = AF_UNIX;
std::strcpy(addr.sun_path, "sandbox/sock");
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof addr);
// demo different status accessors
for (auto it{fs::directory_iterator("sandbox")}; it != fs::directory_iterator(); ++it)
demo_status(*it, it->symlink_status()); // use cached status from directory entry
demo_status("/dev/null", fs::status("/dev/null")); // direct calls to status
demo_status("/dev/sda", fs::status("/dev/sda"));
demo_status("sandbox/no", fs::status("/sandbox/no"));
// cleanup (prefer std::unique_ptr-based custom deleters)
close(fd);
fs::remove_all("sandbox");
}
输出:
"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"/dev/null" is a character device
"/dev/sda" is a block device
"sandbox/no" does not exist
2.23、std::filesystem::temp_directory_path
为临时文件返回一个临时路径
注意:
在 POSIX 系统中,该路径是通过环境变量 TMPDIR
、TMP
、TEMP
以及 TEMPDIR
指定的,如果这些变量没有被设定,则返回默认的路径 /tmp
;
在 Windows 中,路径是通过函数 GetTempPath
给定的。
path temp_directory_path();
path temp_directory_path( std::error_code& ec );
案例:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
std::cout << "Temp directory is " << fs::temp_directory_path() << '\n';
}
输出:
Temp directory is "C:\Windows\TEMP\"
3、文件类型
is_block_file | 判断指定的路径是否为 block 设备 |
is_character_file | 判断指定的路径是否为 character 设备 |
is_directory | 判断指定的路径是否为文件夹 |
is_empty | 判断指定的文件或文件夹是否为空 |
is_fifo | 判断指定的路径是否为命名管道 |
is_other | 判断指定的参数是否为 other 文件 |
is_regular_file | 判断指定的参数是否为常规文件 |
is_socket | 判断指定的参数是否为命名的 IPC socket |
is_symlink | 判断指定的参数是否为符号链接 |
status_known | 检查文件状态是否已知 |
3.1、std::filesystem::is_block_file
定义于
<filesystem>
检查给定的文件状态或路径是否对应于块特殊文件,如 Linux 上的
/dev/sda
或/dev/loop0
第一个函数等效于
s.type() == file_type::block
后两个函数等效于
is_block_file(status(p))
与is_block_file(status(p, ec))
bool is_block_file( std::filesystem::file_status s ) noexcept;
bool is_block_file( const std::filesystem::path& p );
bool is_block_file( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例:
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
namespace fs = std::filesystem;
void demo_status(const fs::path& p, fs::file_status s)
{
std::cout << p;
// alternative: switch(s.type()) { case fs::file_type::regular: ...}
if (fs::is_regular_file(s))
std::cout << " is a regular file\n";
if (fs::is_directory(s))
std::cout << " is a directory\n";
if (fs::is_block_file(s))
std::cout << " is a block device\n";
if (fs::is_character_file(s))
std::cout << " is a character device\n";
if (fs::is_fifo(s))
std::cout << " is a named IPC pipe\n";
if (fs::is_socket(s))
std::cout << " is a named IPC socket\n";
if (fs::is_symlink(s))
std::cout << " is a symlink\n";
if (!fs::exists(s))
std::cout << " does not exist\n";
}
int main()
{
// create files of different kinds
fs::create_directory("sandbox");
fs::create_directory("sandbox/dir");
std::ofstream{"sandbox/file"}; // create regular file
fs::create_symlink("file", "sandbox/symlink");
mkfifo("sandbox/pipe", 0644);
sockaddr_un addr;
addr.sun_family = AF_UNIX;
std::strcpy(addr.sun_path, "sandbox/sock");
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof addr);
// demo different status accessors
for (auto it{fs::directory_iterator("sandbox")}; it != fs::directory_iterator(); ++it)
demo_status(*it, it->symlink_status()); // use cached status from directory entry
demo_status("/dev/null", fs::status("/dev/null")); // direct calls to status
demo_status("/dev/sda", fs::status("/dev/sda"));
demo_status("sandbox/no", fs::status("/sandbox/no"));
// cleanup (prefer std::unique_ptr-based custom deleters)
close(fd);
fs::remove_all("sandbox");
}
输出:
"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"/dev/null" is a character device
"/dev/sda" is a block device
"sandbox/no" does not exist
3.2、std::filesystem::is_character_file
定义于
<filesystem>
第一个函数等效于
s.type() == file_type::character
后两个函数等效于
is_character_file(status(p))
与is_character_file(status(p, ec))
bool is_character_file( std::filesystem::file_status s ) noexcept;
bool is_character_file( const std::filesystem::path& p );
bool is_character_file( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例见 std::filesystem::is_block_file
3.3、std::filesystem::is_directory
定义于
<filesystem>
第一个函数等效于
s.type() == file_type::directory
后两个函数等效于
is_directory(status(p))
与is_directory(status(p, ec))
bool is_directory( std::filesystem::file_status s ) noexcept;
bool is_directory( const std::filesystem::path& p );
bool is_directory( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例见 std::filesystem::is_block_file
3.4、std::filesystem::is_empty
定义于
<filesystem>
bool is_empty( const std::filesystem::path& p );
bool is_empty( const std::filesystem::path& p, std::error_code& ec );
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
第一个函数在底层系统 API 错误上抛出 std::filesystem::filesystem_error
,构建时将 p
作为第一个路径参数,将系统错误代码作为错误代码参数。
如果系统 API 调用失败,第二个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例:
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <iostream>
int main()
{
namespace fs = std::filesystem;
const fs::path tmp_dir{fs::temp_directory_path()};
std::cout << std::boolalpha
<< "Temp dir: " << tmp_dir << '\n'
<< "is_empty(): " << fs::is_empty(tmp_dir) << '\n';
const fs::path tmp_name{tmp_dir / std::tmpnam(nullptr)};
std::cout << "Temp file: " << tmp_name << '\n';
std::ofstream file{tmp_name.string()};
std::cout << "is_empty(): " << fs::is_empty(tmp_name) << '\n';
file << "cppreference.com";
file.flush();
std::cout << "is_empty(): " << fs::is_empty(tmp_name) << '\n'
<< "file_size(): " << fs::file_size(tmp_name) << '\n';
file.close();
fs::remove(tmp_name);
}
输出:
Temp dir: "/tmp"
is_empty(): false
Temp file: "/tmp/fileCqd9DM"
is_empty(): true
is_empty(): false
file_size(): 16
3.5、std::filesystem::is_fifo
定义于
<filesystem>
第一个函数等效于
s.type() == file_type::fifo
后两个函数等效于
is_fifo(status(p))
与is_fifo(status(p, ec))
bool is_fifo( std::filesystem::file_status s ) noexcept;
bool is_fifo( const std::filesystem::path& p );
bool is_fifo( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例见 std::filesystem::is_block_file
3.6、std::filesystem::is_other
定义于
<filesystem>
第一个函数等效于
exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s)
后两个函数等效于
is_other(status(p))
与is_other(status(p, ec))
bool is_other( std::filesystem::file_status s ) noexcept;
bool is_other( const std::filesystem::path& p );
bool is_other( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
3.7、std::filesystem::is_regular_file
定义于
<filesystem>
第一个函数等效于
s.type() == file_type::regular
后两个函数等效于
is_regular_file(status(p))
与is_regular_file(status(p, ec))
bool is_regular_file( std::filesystem::file_status s ) noexcept;
bool is_regular_file( const std::filesystem::path& p );
bool is_regular_file( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例见 std::filesystem::is_block_file
3.8、std::filesystem::is_socket
定义于
<filesystem>
第一个函数等效于
s.type() == file_type::socket
后两个函数等效于
is_socket(status(p))
与is_socket(status(p, ec))
bool is_socket( std::filesystem::file_status s ) noexcept;
bool is_socket( const std::filesystem::path& p );
bool is_socket( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例见 std::filesystem::is_block_file
3.9、std::filesystem::is_symlink
定义于
<filesystem>
第一个函数等效于
s.type() == file_type::symlink
第二和第三个函数等效于
is_symlink(symlink_status(p))
与is_symlink(symlink_status(p, ec))
bool is_symlink( std::filesystem::file_status s ) noexcept;
bool is_symlink( const std::filesystem::path& p );
bool is_symlink( const std::filesystem::path& p, std::error_code& ec ) noexcept;
异常:
如果内存分配失败,任何未标记为 noexcept
的重载函数都可能引发 std::bad_alloc
;
如果系统 API 调用失败,后两个函数会将 std::error_code&
参数设置为系统 API 错误代码;如果未出现错误,则执行 ec.clear()
。
案例见 std::filesystem::is_block_file
3.10、std::filesystem::status_known
定义于
<filesystem>
与
s.type() != file_type::none
相同,用于判断给定的file_status
是否已知
bool status_known( std::filesystem::file_status s ) noexcept;
注意:
不管名称如何,该函数都会检查文件状态 file_type::none
(即发生错误),而不是 file_type::unknown
(即文件存在,但无法确定其类型)。