c++ filesystem详解(3) - 路径
sinye56 2024-12-12 14:51 10 浏览 0 评论
路径是非常重要的概念, filesystem 提供了path类, 下面学习及解析。
1. 问题
在工作中, 跨平台对路径字符的处理是避免不了的, 所以有下面几个问题:
a、目录分隔符怎样处理呢?
b、编码怎样统一?
c、路径的分割怎样处理?
filesystem path出现之前, 工作实践为:
windows/linux统一内部使用目录分隔符/;
windows/linux交互存储使用UTF-8编码;
windows下使用UNICODE API处理,存储交互转化成UTF-8, 避免使用ANSI;
这样基本就解决了跨平台问题, 那么filesystem path是怎样处理的呢?
2. 标准文档
标准文件搬运, 方便阅读记录std::filesystem::path - cppreference.com
路径名拥有下列语法:
- 根名(可选):标识具有多根的文件系统(如 "C:" 或 "//myserver")的根。有歧义的情况下,将组成合法 根名 的最长序列当做 根名。标准库可以在 OS API 所了解的 根名 外,定义额外的 根名。
- 根目录(可选):目录分隔符,若存在,则标记此路径为绝对。若缺失(且异于根名的首元素是文件名),则路径为相对且要求另一路径作为解决此文件名的起始位置。
- 零或多个下列者:
- 文件名:不由目录分隔符或偏好目录分隔符组成的字符序列(操作系统或文件系统可能加上附加限制)。此名称可能标识一个文件、硬链接或目录。辨别两种特殊的 文件名:
- 点:由单个点字符. 构成的文件名是指代当前目录的目录名
- 点点:由两个点字符 .. 构成的文件名是指代父目录的目录名。
- 目录分隔符:正斜杠字符 / 或作为 path::preferred_separator 提供的另一种字符。若重复此字符,则它被处理成单个目录分隔符:/usr///////lib 与 /usr/lib 相同。
path能以下列算法正常化:
- 若路径为空,则停止(空路径的正常形式是空路径)。
- 替换每个 目录分隔符(可以由多重斜杠组成)为单个 path::preferred_separator。
- 替换 根名 中的每个斜杠字符为 path::preferred_separator。
- 移除每个 点 和立即后随的 目录分隔符。
- 移除每个立即后随 目录分隔符 和一个 点点 的非 点点 文件名,还有立即跟随的 目录分隔符。
- 若存在 根目录,则移除立即跟随它们的所有 点点 及任何 目录分隔符。
- 若最终文件名是 点点,则移除任何尾随的 目录分隔符。
- 若路径为空,则添加一个 点(./ 的正常形式是 .)。
路径可由 begin() 与 end() 函数返回的迭代器逐元素进行遍历,这会以通用格式查看路径,并在根名、根目录及后继文件名元素上迭代(跳过目录分隔符,除了标识根目录者)。若路径中的最后元素是目录分隔符,则最后的迭代器将解引用为空元素。
调用任何的 path 非 const 成员函数会令所有引用该对象元素的迭代器失效。
若 OS 使用异于上述可移植通用语法的原生语法,则库函数被定义为接受“受检测格式”,以接受两种格式的路径名:当且仅当受检测格式匹配通用格式,但不为操作系统作为原生路径接受,才采用受检测格式参数。原生格式在目录路径名和文件路径名有别的 OS 上,若通用路径名以目录分隔符终止,则将它当做目录路径,否则当做常规文件。
任何情况下,path 类表现如同它以原生格式存储路径名,并自动于所需场合转换它为通用格式(每个成员函数都指定它转译的路径格式)。
POSIX 系统上,通用格式就是原生格式,并且没有必要区别或转换它们。
路径可隐式转换自及转换成 std::basic_string,这使得在文件 API 上使用它们可行。
流运算符使用 std::quoted 以使空白不会导致其后通过流输入运算符的读取发生截断。
分解成员函数(如 extension)返回 filesystem::path 对象而不是如其他 API 那样返回字符串对象。
成员类型与常量
类型 | 定义 |
value_type | 文件系统原生编码所用的字符类型: POSIX 上为 char,Windows 上为 wchar_t |
string_type | std::basic_string<value_type> |
const_iterator | value_type 为 path 的常量老式输入迭代器 (LegacyInputIterator) ,符合老式双向迭代器 (LegacyBidirectionalIterator) 的所有要求,但对于两个相等且可解引用的 const_iterator 类型的迭代器 a 与 b,不要求 *a 与 b 指代同一对象。const_iterator 是否实际为[老式双向迭代器* (LegacyBidirectionalIterator) ](https://zh.cppreference.com/w/cpp/named_req/BidirectionalIterator)是未指定的。 |
iterator | const_iterator 的别名 |
format | 确定如何解读路径名的字符串表示亦定义下列枚举项: 常量解释 native_format原生路径格式 generic_format通用路径格式 auto_format实现定义格式,如果可能就自动检测 (枚举) |
成员常量
constexpr value_type preferred_separator [static] | 在可移植的 / 之外可用的另一种目录分隔符。 Windows 上它是反斜杠字符 \。 POSIX 上它是与可移植分隔符相同的斜杠 / (公开静态成员常量) |
成员函数
(构造函数) | 构造一个 path (公开成员函数) |
(析构函数) | 销毁 path 对象 (公开成员函数) |
operator= | 赋值另一个路径 (公开成员函数) |
assign | 赋值内容 (公开成员函数) |
连接 | |
append operator/= | 以目录分隔符向路径添加元素 (公开成员函数) |
concat operator+= | 连接两个路径而不加入目录分隔符 (公开成员函数) |
修改器 | |
clear | 擦除内容 (公开成员函数) |
make_preferred | 转换目录分隔符为首选目录分隔符 (公开成员函数) |
remove_filename | 移除文件名路径组分 (公开成员函数) |
replace_filename | 以另一路径替换最末的路径组分 (公开成员函数) |
replace_extension | 替换扩展名 (公开成员函数) |
swap | 交换两个路径 (公开成员函数) |
格式观察器 | |
c_str native operator string_type | 返回路径的原生版本 (公开成员函数) |
string wstring u8string u16string u32string | 返回转换到字符串的原生路径名格式的路径 (公开成员函数) |
generic_string generic_wstring generic_u8string generic_u16string generic_u32string | 返回转换到字符串的通用路径名格式 (公开成员函数) |
比较 | |
compare | 以字典序比较两个路径的词法表示 (公开成员函数) |
生成 | |
lexically_normal lexically_relative lexically_proximate | 转换路径到正常形式 转换路径到相对形式 转换路径到近似形式 (公开成员函数) |
分解 | |
root_name | 若存在则返回路径的根名 (公开成员函数) |
root_directory | 若存在则返回路径的根目录 (公开成员函数) |
root_path | 若存在则返回路径的根路径 (公开成员函数) |
relative_path | 返回相对根路径的路径 (公开成员函数) |
parent_path | 返回父路径的路径 (公开成员函数) |
filename | 返回文件名路径组分 (公开成员函数) |
stem | 返回主干路径组分(不带扩展名的文件名) (公开成员函数) |
extension | 返回文件扩展名路径组分 (公开成员函数) |
查询 | |
empty | 检查路径是否为空 (公开成员函数) |
has_root_path has_root_name has_root_directory has_relative_path has_parent_path has_filename has_stem has_extension | 检查对应路径元素是否非空 (公开成员函数) |
is_absoluteis_relative | 检查 root_path() 是否唯一标识文件系统位置 (公开成员函数) |
迭代器 | |
beginend | 将路径作为元素序列访问的迭代器 (公开成员函数) |
非成员函数
swap(std::filesystem::path) | 交换两个路径 (函数) |
hash_value | 计算路径对象的散列值 (函数) |
operator== operator!=(C++20 前) operator<(C++20 前) operator<=(C++20 前) operator>(C++20 前) operator>=(C++20 前) operator<=>(C++20) | 以字典序比较两个路径 (函数) |
operator/ | 用目录分隔符连接两个路径 (函数) |
operator<> | 进行路径上的流输入及输出 (函数) |
u8path(C++17) (C++20 中弃用) | 从 UTF-8 编码的源创建 path (函数) |
辅助类
在命名空间 std 定义 | |
std::hash(C++17) | std::filesystem::path 的散列支持 (类模板特化) |
std::filesystem::path构造函数
path() noexcept; | (1) | (C++17 起) |
path( const path& p ); | (2) | (C++17 起) |
path( path&& p ) noexcept; | (3) | (C++17 起) |
path( string_type&& source, format fmt = auto_format ); | (4) | (C++17 起) |
template< class Source > path( const Source& source, format fmt = auto_format ); | (5) | (C++17 起) |
template< class InputIt > path( InputIt first, InputIt last, format fmt = auto_format ); | (6) | (C++17 起) |
template< class Source > path( const Source& source, const std::locale& loc, format fmt = auto_format ); | (7) | (C++17 起) |
template< class InputIt > path( InputIt first, InputIt last, const std::locale& loc, format fmt = auto_format ); | (8) | (C++17 起) |
构造新的 path 对象。
1) 构造空路径。
2) 复制构造函数。构造一个路径,其原生与通用格式的路径名均与 p 相同
3) 移动构造函数。构造一个路径,其原生与通用格式的路径名均与 p 相同,p 留在合法而未指定的状态。
4-6) 从 source (4,5) 提供的字符序列构造路径(按 fmt 指定的格式转译),源可以是一个指向空终值字符/宽字符序列的指针或输入迭代器,std::basic_string 或 std::basic_string_view,或作为一对输入迭代器 [first, last) 提供 (6)。允许任何字符类型 char、char8_t (C++20 起)、char16_t、char32_t、wchar_t,而且原生字符集的转换方法依赖于 source 所用的字符类型
若源字符类型是 char8_t,则使用从 UTF-8 到原生文件系统编码的转换。 | (C++20 起) |
7,8) 从 source (7) 提供的从字符序列构造路径(按 fmt 指定的格式转译),源可以是指向空终止字符序列的指针或输入迭代器,std::string,std::basic_string_view,或由一对输入迭代器 [first, last) (8) 所代表。仅允许的字符类型是 char。用 loc 进行字符编码转换。若 value_type 是 wchar_t,则使用 loc 的 std::codecvt<wchar_t, char, std::mbstate_t> 平面从宽字符转换。否则,首先用 std::codecvt<wchar_t, char, std::mbstate_t> 平面转换到宽字符,再用 loc 的 std::codecvt<wchar_t,value_type> 平面转换到文件系统原生字符类型。
仅若 Source 与 path 不是同一类型,而且:
- Source 是 std::basic_string 或 std::basic_string_view 的特化,或
- std::iterator_traits[std::decay_t](http://zh.cppreference.com/w/cpp/types/decay)<Source>::value_type 合法并代表可能有 const 限定的编码字符类型(char、char8_t、 (C++20 起)char16_t、char32_t 或 wchar_t)
(5) 与 (7) 才参与重载决议。
参数
p | 要复制的路径 |
source | std::basic_string,std::basic_string_view,指向空终止字符串的指针,或拥有字符值类型并指向空终止字符序列的的输入迭代器(对于重载 (7) 字符类型必须是 char) |
first, last | 一对指定字符序列的老式输入迭代器 (LegacyInputIterator) |
fmt | path::format 类型的枚举项,指定路径名格式如何转译 |
loc | 定义编码转换所用的本地环境 |
类型要求 | |
-InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 。 | |
-InputIt 的值类型 必须是字符类型 char、 char8_t (C++20 起)、 wchar_t、 char16_t 及 char32_t 之一, 以使用重载 (6)。 | |
-InputIt 的值类型必须是 char,以使用 (8)。 |
异常
2,4-8) 可能会抛出由实现定义的异常。
** 注解**
关于从 Unicode 字符串生成可移植路径名,见 u8path。 | (C++20 前) |
源为 char8_t 的序列时,path 构造函数支持从 UTF-8 字符串创建。 | (C++20 起) |
- 上一篇:Linux超能力命令sudo详解
- 下一篇:Linux文件类基础命令(包含原理讲解)
相关推荐
- linux 查看当前应用内存状况,以及内存参数含义
-
1、查看进程号ps-ef|greptomcat2、查看当前内存分配,200ms打印一次jstat-gc进程号2001jstat-gc344802001S0CS1C...
- 如何显示 Linux 系统上的可用内存?这几个命令很好用!
-
在Linux系统中,了解可用内存是优化系统性能、故障排查以及资源管理的重要一环。本文将详细介绍如何在Linux系统上显示可用内存,包括多种方法和工具的使用。在讨论可用内存之前,我们需要了解一些...
- Linux 下查看内存使用情况方法总结
-
Q:我想监视Linux系统的内存使用情况,在Linux下有哪些视图或者命令行工具可用呢?在做Linux系统优化的时候,物理内存是其中最重要的一方面。自然的,Linux也提供了非常多的方法来监控宝贵的内...
- 2、linux命令-用户管理
-
linux命令-用户管理用户切换[root@eric~]#sueric#切换到用户eric[eric@ericroot]$[eric@ericroot]$su#切换到rootPas...
- Centos 7 进入单用户模式详解
-
1、开机在启动菜单按e进入编辑模式找到linux16行,在最后添加init=/bin/sh编辑完后,按ctrl+x退出2、进单用户模式后,使用passwd修改密码,提示以下错误:passwd:Aut...
- 每日一个Linux命令解析——newusers
-
newusers:在Linux系统中,newusers是一个用于批量创建用户的命令。它从一个文件中读取多行用户信息,每行描述一个用户的详细信息,并根据这些信息创建多个用户或对现有用户进行批量修改。一...
- openEuler操作系统管理员指南:管理用户与用户组
-
在Linux中,每个普通用户都有一个账户,包括用户名、密码和主目录等信息。除此之外,还有一些系统本身创建的特殊用户,它们具有特殊的意义,其中最重要的是管理员账户,默认用户名是root。同时Linux也...
- Linux用户管理
-
1、用户信息文件/etc/passwdroot:x:0:0:root:/root:/bin/bash第一列:用户名第二列:密码位第三列:用户ID0超级用户UID。如果用户UID...
- centos7基础-用户、组、权限管理
-
用户和组(1)用户、组、家目录的概念linux系统支持多用户,除了管理员,其他用户一般不应该使用root,而是应该向管理员申请一个账号。组类似于角色,系统可以通过组对有共性的用户进行统一管理。每个用户...
- LINUX基础 ----------组及用户的概念
-
在Linux中,用户和组都是非常重要的概念,可以控制文件访问权限和资源的管理。用户是标识一个进程、应用程序或系统管理员的账号,Linux中每个用户用一个用户ID(UID)来标识。对于一个...
- 从零入门Linux(四)用户与权限管理
-
在Linux系统中,用户和权限管理是系统安全的重要组成部分。通过合理配置用户和权限,可以确保系统的安全性和资源的合理分配。以下是一些与用户和权限管理相关的常用命令和概念。1.用户管理1.1添加...
- 如何在 Linux 中管理用户?
-
在Linux系统中,用户是系统资源的主要使用者,每个用户都有一个唯一的标识符(用户ID)。为了更好地组织和管理用户,Linux还引入了用户组的概念。用户组是用户的集合,有助于更有效地分配权限和资...
- 在 Linux 中将用户添加到特定组的四种方法
-
在Linux多用户操作系统中,用户组管理是系统安全架构的基石。通过合理的组权限分配,管理员可以实现:精确控制文件访问权限(chmod775project/)简化批量用户权限管理(setfacl-...
- 我不是网管 - 如何在Ubuntu Linux下创建sudo用户
-
Sudo用户是Linux系统的普通用户,具有一定的管理权限,可以对系统执行管理任务。在Linux中,root是超级用户,拥有完全的管理权限,但不建议将root凭证授予其他用户或作为r...
- Linux创建普通用户,为密钥方式登录做准备
-
Hi,我是聪慧苹果8,就是江湖上人见人爱、花见花开,土到掉榨的Linux爱好者,一起学习吧!上一篇关于SSH安全加固的文字,有网友点评通过密钥登录更加安全,先创建一个普通用户,拒绝直接使用密码登录,这...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle忘记用户名密码 (59)
- oracle11gr2安装教程 (55)
- mybatis调用oracle存储过程 (67)
- oracle spool的用法 (57)
- oracle asm 磁盘管理 (67)
- 前端 设计模式 (64)
- 前端面试vue (56)
- linux格式化 (55)
- linux图形界面 (62)
- linux文件压缩 (75)
- Linux设置权限 (53)
- linux服务器配置 (62)
- mysql安装linux (71)
- linux启动命令 (59)
- 查看linux磁盘 (72)
- linux用户组 (74)
- linux多线程 (70)
- linux设备驱动 (53)
- linux自启动 (59)
- linux网络命令 (55)
- linux传文件 (60)
- linux打包文件 (58)
- linux查看数据库 (61)
- linux获取ip (64)
- linux进程通信 (63)