自学内容网 自学内容网

C++17 filesystem 库 学习笔记

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) 一致;
    • 对不含上面情况的其他情形,函数报错;
  • 如果 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) 的表现相同。
  • 如果 from 是文件夹,并且在 options 中设置了 copy_options::create_symlinks,函数将会报错,相应的错误代码为 std::make_error_code(std::errc::is_a_directory)
  • 如果 from 是文件夹,而 options 中设置了 copy_options::recursivecopy_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)
  • 对 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 中没有设置控制选项
      • 否则,如果在 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_symlinkcreate_directory_symlink

第二个函数依据 from 是文件还是文件夹,将以 f(read_symlink(from), to, ec) 的形式调用函数 create_symlinkcreate_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

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

为临时文件返回一个临时路径

注意:
在 POSIX 系统中,该路径是通过环境变量 TMPDIRTMPTEMP 以及 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(即文件存在,但无法确定其类型)。


原文地址:https://blog.csdn.net/qq_29695701/article/details/140260328

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!