【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(一)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南

1. 引言

1.1 为什么需要了解C++ Filesystem

在编程世界中,文件和目录操作是不可或缺的一部分。无论你是在开发一个复杂的数据分析工具,还是一个简单的文本编辑器,你都需要与文件系统(Filesystem)进行交互。C++ Filesystem库提供了一种标准化和跨平台的方式来进行这些操作。

“The only way to do great work is to love what you do.” - Steve Jobs

这句话不仅适用于职业生涯,也适用于编程。当你了解并掌握了如何与文件系统交互,你会发现编程不仅是一项技术活动,更是一种艺术。

技术对比

方法 用途 平台兼容性
std::filesystem::create_directory 创建目录 跨平台
std::filesystem::remove 删除文件或目录 跨平台
std::filesystem::copy 复制文件或目录 跨平台

1.2 C++ Filesystem库的重要性

C++ Filesystem库的出现,让文件和目录操作变得更加简单和直观。在这之前,程序员通常需要依赖于操作系统特定的API,这不仅增加了代码的复杂性,也降低了代码的可移植性。

“Simplicity is the ultimate sophistication.” - Leonardo da Vinci

正如达·芬奇所说,简单是最高级别的复杂。C++ Filesystem库就是这样一个简单但功能强大的工具。

代码示例

#include <filesystem>
namespace fs = std::filesystem;
int main() {
    fs::create_directory("new_folder");
    fs::remove("old_folder");
}

1.3 博客目标和读者群

本博客的目标是为读者提供一个全面而深入的指南,以掌握C++ Filesystem库的各个方面。无论你是一个有经验的C++开发者,还是一个初学者,你都会在这里找到有用的信息。

“Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.” - Maimonides

这篇博客就像是教你如何钓鱼,而不仅仅是给你一条鱼。通过深入了解C++ Filesystem库,你将能够更有效地解决问题,而不是仅仅依赖于现有的解决方案。

技术对比

特性 C++ Filesystem 传统C++ I/O Python I/O
代码简洁性
性能
平台兼容性

2. C++ Filesystem库简介

2.1 历史背景

C++ Filesystem库是C++17标准的一部分,它的出现填补了C++长久以来在文件和目录操作方面的空白。在这之前,开发者通常需要使用操作系统特定的API或第三方库。

“Those who cannot remember the past are condemned to repeat it.” - George Santayana

了解C++ Filesystem库的历史背景,有助于我们更好地理解它的设计哲学和应用场景。

技术对比

年份 发展事件
2011 Boost Filesystem库发布
2014 C++14标准发布,但未包含Filesystem库
2017 C++17标准发布,正式引入Filesystem库

2.2 主要功能和用途

C++ Filesystem库提供了一系列用于文件和目录操作的API,包括但不限于创建、删除、复制文件和目录,以及查询文件属性等。

“The function of good software is to make the complex appear to be simple.” - Grady Booch

这个库就像是一个多功能瑞士军刀,无论你需要进行哪种文件操作,它都能为你提供方便。

代码示例

#include <filesystem>
namespace fs = std::filesystem;
int main() {
    // 创建目录
    fs::create_directory("example_folder");
    // 复制文件
    fs::copy("source.txt", "destination.txt");
    // 删除文件
    fs::remove("unwanted_file.txt");
}

2.3 如何在项目中引入Filesystem库

使用C++ Filesystem库非常简单,你只需要包含相应的头文件,并使用相应的命名空间。

“The beginning is the most important part of the work.” - Plato

开始总是最重要的,一旦你了解了如何在项目中引入这个库,你就已经迈出了掌握它的第一步。

代码示例

// 引入头文件
#include <filesystem>
// 使用命名空间
namespace fs = std::filesystem;

技术对比

库名称 引入方式 平台兼容性
C++ Filesystem #include <filesystem> 跨平台
POSIX #include <unistd.h> Unix/Linux
Windows API #include <windows.h> Windows

3. 文件操作基础

3.1 创建文件

在C++中,使用std::filesystem::create_directoriesstd::filesystem::create_directory(标准文件系统库中的方法)可以轻松创建文件。但在创建文件之前,我们通常会有一个疑问:我真的需要这个文件吗?

这个问题看似简单,实际上涉及到我们对“需求和供应”的基本认识。当你觉得需要某个文件时,很可能是因为你已经预见到了它在未来的用途。这与我们在日常生活中对物品的需求有异曲同工之妙。

#include <filesystem>
namespace fs = std::filesystem;
int main() {
    fs::create_directories("new_folder/sub_folder");
    fs::create_directory("another_folder");
}

3.2 读取文件

读取文件通常使用std::ifstream(Input File Stream)来完成。这里的“输入”并不是说文件本身是输入,而是从程序的角度看,文件内容被“输入”到程序中。

人们常说“知识就是力量”,但在获取知识(或者说读取文件)之前,最好先了解一下你要面对的是什么。这就像在阅读一本厚重的名著之前先浏览目录,了解大致内容。

#include <fstream>
#include <iostream>
#include <string>
int main() {
    std::ifstream file("example.txt");
    std::string line;
    while (std::getline(file, line)) {
        std::cout << line << std::endl;
    }
}

3.3 写入文件

写入文件在C++中通常使用std::ofstream(Output File Stream)。这里的“输出”意味着数据从程序“输出”到文件。

写入文件就像是在日记中记录自己的心情和事件,你可能不会立即看到它的价值,但当你回头看时,你会发现它记录了你的成长和变化。

#include <fstream>
int main() {
    std::ofstream file("example.txt");
    file << "Hello, World!" << std::endl;
}

3.3.1 文件写入模式

在使用std::ofstream时,你可以选择不同的文件写入模式,例如std::ios::app(追加模式)和std::ios::trunc(截断模式)。

模式 描述
std::ios::app 追加到文件末尾
std::ios::trunc 截断现有文件
// 追加模式
std::ofstream file("example.txt", std::ios::app);
file << "Additional line" << std::endl;

3.4 文件属性和权限

在C++中,std::filesystem::permissionsstd::filesystem::status等函数允许你查询和修改文件属性和权限。

当你设置文件权限时,你其实是在界定哪些用户可以做什么,这与社会规范中对个体行为的限制有些相似。正确的权限设置可以防止未经授权的访问,就像合适的社会规范可以维护社会秩序。

#include <filesystem>
namespace fs = std::filesystem;
int main() {
    fs::permissions("example.txt", fs::perms::owner_all);
}

4. 目录操作基础

4.1 创建目录

4.1.1 std::filesystem::create_directory

在C++中,使用std::filesystem::create_directory(创建目录)方法是最直接的方式来创建一个新目录。这个函数非常直观,只需要一个路径参数。

#include <filesystem>
namespace fs = std::filesystem;
int main() {
    fs::create_directory("new_directory");
}

底层原理: 实际上,这个函数会调用操作系统的API来进行目录创建。在Linux系统中,它可能会调用mkdir系统调用。

4.1.2 选择合适的目录名

选择目录名可能看似简单,但实际上,一个好的目录名可以让你的代码更易于维护。比如,避免使用空格和特殊字符,这样在命令行操作时会更方便。

心理学角度: 人们通常会对清晰、简单的信息更容易记忆。这也是为什么我们更容易记住有意义的单词而不是随机的字符组合。

4.1.3 权限设置

在创建目录时,你也可以设置其权限,这通常在Linux系统中更为常见。你可以使用std::filesystem::perms(权限)枚举来设置。

fs::create_directory("new_directory", fs::perms::owner_all);

底层原理: 在Linux系统中,这实际上是通过chmod系统调用来实现的。

方法 优点 缺点
std::filesystem::create_directory 简单、直接 功能有限
std::filesystem::create_directories 可创建多级目录 相对复杂

4.2 遍历目录

4.2.1 std::filesystem::directory_iterator

使用std::filesystem::directory_iterator(目录迭代器)可以方便地遍历一个目录下的所有文件和子目录。

for(auto& p: fs::directory_iterator("some_directory")) {
    std::cout << p.path() << std::endl;
}

底层原理: 这个迭代器实际上是通过系统调用,如Linux中的readdir,来获取目录下的所有项。

4.2.2 深度优先与广度优先

在遍历目录时,你可以选择深度优先或广度优先。深度优先通常用于搜索操作,而广度优先则更适用于快速查找。

心理学角度: 人们在面对复杂任务时,通常会自然地采取一种分而治之的策略,这与深度优先搜索有异曲同工之妙。

方法 优点 缺点
std::filesystem::directory_iterator 简单、易用 只能进行浅层遍历

4.3 移动和重命名目录

4.3.1 std::filesystem::rename

在C++中,std::filesystem::rename(重命名)函数用于重命名或移动文件和目录。这个函数接受两个参数:源路径和目标路径。

fs::rename("old_directory", "new_directory");

底层原理: 在Linux系统中,这通常通过rename系统调用来实现。

4.3.2 重命名的注意事项

重命名或移动目录时,确保目标路径不存在或可覆盖,否则操作会失败。

心理学角度: 人们通常不喜欢改变,尤其是突然的改变。因此,在编程中,如果你需要重命名一个被广泛使用的目录,最好是先通知团队成员。

4.3.3 std::filesystem::copy

除了重命名,你还可以使用std::filesystem::copy(复制)函数来复制目录。

fs::copy("source_directory", "destination_directory", fs::copy_options::recursive);

底层原理: 这个函数实际上会递归地复制目录下的所有文件和子目录。

方法 优点 缺点
std::filesystem::rename 快速、原子操作 不能跨文件系统
std::filesystem::copy 可以跨文件系统 相对慢

4.4 删除目录

4.4.1 std::filesystem::remove

删除目录在C++中是一个相对简单的操作,通常使用std::filesystem::remove(删除)函数。

fs::remove("directory_to_remove");

底层原理: 在Linux系统中,这通常是通过rmdir系统调用来完成的。

4.4.2 删除的风险和责任

删除是一个不可逆的操作,因此需要谨慎处理。确保备份重要数据,并在删除前进行确认。

心理学角度: 人们对失去东西通常会有更强烈的反应,这被称为“损失厌恶”。因此,在编程中,删除操作应该设计得尽可能安全。

方法 优点 缺点
std::filesystem::remove 简单、直接 不可逆

5. 路径操作和概念

5.1 绝对路径和相对路径

在C++ Filesystem库中,路径(Path)是一个核心概念。路径可以分为两种:绝对路径(Absolute Path)和相对路径(Relative Path)。

  • 绝对路径:从文件系统的根目录开始,一直到目标文件或目录。
  • 相对路径:从某个特定目录开始,一直到目标文件或目录。

5.1.1 为什么需要两种路径

想象一下,你在一个陌生的城市中寻找一家餐厅。如果有人给你一个详细的地图,从城市的中心点一直到餐厅,那就像是绝对路径。但如果你已经在一个熟悉的街区,只需要几个简单的方向指示,那就像是相对路径。

代码示例
#include <filesystem>
namespace fs = std::filesystem;
// 绝对路径
fs::path abs_path = "/home/user/documents/file.txt";
// 相对路径
fs::path rel_path = "documents/file.txt";

5.2 路径拼接

路径拼接(Path Concatenation)是将两个或多个路径片段合并成一个完整路径的过程。

5.2.1 如何拼接路径

拼接路径就像是拼图游戏,每个路径片段都是一个拼图块。正确地拼接它们,你就能得到一个完整的图片,也就是完整的路径。

代码示例
fs::path base_path = "/home/user";
fs::path file = "documents/file.txt";
fs::path full_path = base_path / file;  // 输出:/home/user/documents/file.txt

5.3 路径解析

路径解析(Path Resolution)是将一个路径字符串解析成其各个组成部分的过程。

5.3.1 解析的重要性

解析路径就像是读懂一首诗。每个目录和文件都像是诗中的一个词或短语,只有理解了它们的意义和关系,你才能真正“读懂”这个路径。

代码示例
fs::path p = "/home/user/documents/file.txt";
std::cout << "Parent path: " << p.parent_path() << std::endl;  // 输出:/home/user/documents
std::cout << "Filename: " << p.filename() << std::endl;  // 输出:file.txt

5.3.2 方法对比

方法 功能描述 示例
parent_path() 获取父路径 /home/user/documents
filename() 获取文件名 file.txt
extension() 获取文件扩展名 .txt
stem() 获取不带扩展名的文件名 file

这些方法都是C++ Filesystem库中用于路径解析的基础工具,掌握它们能让你在文件和目录操作中更加得心应手。

“The shortest answer is doing.” - Lord Herbert

通过实践来掌握这些概念和方法,你将能更有效地利用C++ Filesystem库,从而提高你的编程效率和代码质量。


【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(二)https://developer.aliyun.com/article/1467853


目录
相关文章
|
13天前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
46 12
|
7月前
|
算法 C++ 容器
C++标准库(速查)总结
C++标准库(速查)总结
155 6
|
4月前
|
XML 网络协议 API
超级好用的C++实用库之服务包装类
通过本文对Boost.Asio、gRPC和Poco三个超级好用的C++服务包装类库的详细介绍,开发者可以根据自己的需求选择合适的库来简化开发工作,提高代码的效率和可维护性。每个库都有其独特的优势和适用场景,合理使用这些库可以极大地提升C++开发的生产力。
86 11
|
4月前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
6月前
|
安全 编译器 C++
【C++11】新特性
`C++11`是2011年发布的`C++`重要版本,引入了约140个新特性和600个缺陷修复。其中,列表初始化(List Initialization)提供了一种更统一、更灵活和更安全的初始化方式,支持内置类型和满足特定条件的自定义类型。此外,`C++11`还引入了`auto`关键字用于自动类型推导,简化了复杂类型的声明,提高了代码的可读性和可维护性。`decltype`则用于根据表达式推导类型,增强了编译时类型检查的能力,特别适用于模板和泛型编程。
55 2
|
7月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
113 5
|
7月前
|
存储 自然语言处理 程序员
C++常用基础知识—STL库(1)
C++常用基础知识—STL库(1)
121 1
|
7月前
|
C++
C++ 20新特性之结构化绑定
在C++ 20出现之前,当我们需要访问一个结构体或类的多个成员时,通常使用.或->操作符。对于复杂的数据结构,这种访问方式往往会显得冗长,也难以理解。C++ 20中引入的结构化绑定允许我们直接从一个聚合类型(比如:tuple、struct、class等)中提取出多个成员,并为它们分别命名。这一特性大大简化了对复杂数据结构的访问方式,使代码更加清晰、易读。
89 0
|
3月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
2月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
54 16
下一篇
oss创建bucket