开发者

C++17 Filesystem 实用教程

目录
  • 什么是 std::filesystem?
  • 为什么使用 std::filesystem?
  • std::filesystem 常用功能
    • 1. 检查文件和目录是否存在
    • 2. 创建和删除目录
    • 3. 遍历目录
    • 4. 查询文件属性
    • 5. 复制和重命名文件
    • 6. 处理符号链接
  • 路径相关操作
    • 7.1 路径组合
    • 7.2 获取路径组件
    • 7.3 相对路径计算
    • 7.4 路径分解与迭代
    • 7.5 词法规范化路径
    • 7.6 路径比较
    • 7.7 路径拼接
    • 7.js8 检查路径特性
    • 路径替换操作
    • 注意事项:
  • 最佳实践
    • 限制性
      • 结论

        C++17 标准带来了 std::filesystem库, 提供了强大的工具来处理文件路径, 目录以及其他与文件系统相关的操作. 这篇文章适合 C++ 初学者以及希望掌握 C++17 新特性的开发者, 旨在帮助他们高效地完成文件系统相关任务.

        什么是 std::filesystem?

        std::filesystem 是 C++ 标准库的一部分, 位于 std::filesystem 名称空间中. 它提供了一个平台 独立的方式来与文件系统交互, 支持目录导航, 查询文件属性和实现文件操作等功能.

        为什么使用 std::filesystem?

        在 C++17 之前, 开发者依赖于平台特定的 API 或第三方库进行文件操作, 导致可移植性的挑战. 使用 std::filesystem, 您可以获得:

        • 跨平台支持: 为 Windows, linux 和 MACOS 提供统一的 API.
        • 便据性: 提供相关文件操作的直观函数.
        • 性能: 接口实现根据平台做了优化处理.

        std::filesystem 常用功能

        1. 检查文件和目录是否存在

        #include <filesystem>
        #include <IOStream>
        
        namespace fs = std::filesystem;
        
        int main() {
          fs::path filePath = "example.txt";
          if (fs::exists(filePath)) {
            std::cout << "文件存在!\n";
          } else {
            std::cout << "文件不存在.\n";
          }
          return 0;
        }
        

        为了保持代码简洁, 后续代码中将不再包含头文件和main函数体, 读者可以从文末的源码链接获取完整源代码.

        2. 创建和删除目录

        fs::path dirPath = "new_directory";
        fs::create_directory(dirPath);  // 创建单个目录
        fs::remove(dirPath);            // 删除目录
        

        3. 遍历目录

        fs::path dirPath = "."; http://www.devze.com// 当前目录
        for (const auto& entry : fs::recursive_directory_iterator(dirPath)) {
            std::cout << entry.path() << std::endl;
        }
        

        此示例会递归列出当前目录及其所有子目录中的文件和文件夹.

        4. 查询文件属性

        fs::path filePath = "example.txt";
        if (fs::exists(filePath)) {
          std::cout << "文件大小: " << fs::file_size(filePath) << " 字节\n";
          std::cout << "是否为正解文件: " http://www.devze.com<< fs::is_regular_file(filePath) << "\n";
          std::cout << "文件最后修改时间: "
                    << fs::last_write_time(filePath).time_since_epoch().count()
                    << "\n";
        }
        

        5. 复制和重命名文件

        fs::copy("source.txt", "destination.txt", fs::copy_options::overwrite_existing); // 复制文件
        fs::rename("old_name.txt", "new_name.txt"); // 重命名文件
        

        6. 处理符号链接

        fs::path symlinkPath = "symbolic_link";
        fs::path targetPath = "target_file";
        fs::create_symlink(targetPath, symlinkPath);  // 创建符号链接
        if (fs::is_symlink(symlinkPath)) {
          std::cout << symlinkPath << " 是符号链接, 指向 "
                    << fs::read_symlink(symlinkPath) << std::endl;
        }
        

        路径相关操作

        7.1 路径组合

        // 1. 路径组合
        fs::path base = "/home/user/documents";
        fs::path file = "report.pdf";
        fs::path fullPath = base / file;  // 使用 / 操作符组合路径
        std::cout << "组合路径: " << fullPath << std::endl;
        

        输出

        组合路径: "/home/user/documents/report.pdf"

        7.2 获取路径组件

        fs::path filepath = "/home/user/documents/report.pdf";
        std::cout << "文件名: " << filepath.filename() << std::endl;
        std::cout << "主文件名: " << filepath.stem() << std::endl;
        std::cout << "扩展名: " << filepath.extension() << std::endl;
        std::cout << "父路径: " << filepath.parent_path() << std::endl;
        

        输出

        文件名: "report.pdf"

        主文件名: "report"

        扩展名: ".pdf"

        父路径: "/home/user/documents"

        7.3 相对路径计算

        fs::path p1 = "/home/user/documents";
        fs::path p2 = "/home/user/pictures";
        fs::path rel = fs::relative(p2, p1);  // 计算从 p1 到 p2 的相对路径
        std::cout << "相对路径: " << rel << std::endl;  // ../pictures
        

        输出

        相对路径: "../pictures"

        7.4 路径分解与迭代

        fs::path complex = "/home/user/documents/work/report.pdf";
        std::cout << "路径分解:" << std::endl;
        for (const auto& part : complex) {
          std::cout << "  " << part << std::endl;
        }
        

        输出

        路径分解:

          "/"

          "home"

          "user"

          "documents"

          "work"

          "report.pdf"

        7.5 词法规范化路径

        fs::path messy = "home/user/../user/./documents/report.pdf";
        std::cout << "规范化路径: " << messy.lexically_normal() << std::endl;
        

        输出

        规范化路径: "home/user/documents/report.pdf"

        7.6 路径比较

        // 使用 std::filesystem::equivalent 检查两个路径是否指向同一文件
        fs::path linkPath =
            "link_to_report.pdf";  // 假设这是一个指向 report.pdf 的符号链接
        fs::path actualPath = "documents/report.pdf";
        try {
          if (fs::equivalent(linkPath, actualPath)) {
            std::cout << "路径 " << linkPath << " 和 " << actualPath
                      << " 指向同一文件." << std::endl;
          } else {
            std::cout << "路径 " << linkPath << " 和 " << actualPath
                      << " 不指向同一文件." << std::endl;
          }
        } catch (const fs::filesystem_error& e) {
          std::cerr << "文件系统错误: " << e.what() << std::endl;
        }
        

        7.7 路径拼接

        fs::path prefix = "backup_";
        fs::path filename = "report.pdf";
        fs::path newpath = prefix.string() + filename.string();
        std::cout << "拼接路径: " << newPath << std::endl;
        

        输出

        拼接路径: "backup_report.pdf"

        7.8 检查路径特性

        fs::path checkPath = "/home/user/documents/report.pdf";
        std::cout << "是否为绝对路径: " << checkPath.is_absolute() <<http://www.devze.com std::endl;
        std::cout << "是否有扩展名: " << checkPath.has_extension() << std::endl;
        std::cout << "是否有文件名: " << checkPath.has_filename() << std::endl;
        std::cout << "是否有父路径: " << checkPath.has_parent_path() << std::endl;
        

        输出

        是否为绝对路径: 1

        是否有扩展名: 1

        是否有文件名: 1

        是否有父路径: 1

        路径替换操作

        fs::path modPath = "/home/user/documents/report.pdf";
        modPath.replace_filename("newreport.dochttp://www.devze.com");
        std::cout << "替换文件名后: " << modPath << std::endl;
        modPath.replace_extension(".txt");
        std::cout << "替换扩展名后: " << modPath << std::endl;
        

        输出

        替换文件名后: "/home/user/documents/newreport.doc"

        替换扩展名后: "/home/user/documents/newreport.txt"

        注意事项:

        • 路径操作是纯字符串操作, 不涉及实际文件系统
        • 这些操作在 Windows 和 Unix 系统上都能正常工作
        • 使用 / 操作符组合路径比直接字符串拼接更安全
        • lexically_normal() 可以清理路径中的 . 和 ..

        最佳实践

        • 错误处理:

          • 使用异常处理来捕获和管理错误情况. 许多 std::filesystem 函数会抛出 std::filesystem::filesystem_error, 例如在没有删除权限时.
        • 路径类型:

          • 使用 fs::absolute 将相对路径转换为绝对路径, 以确保路径的完整性和清晰性.
        • 性能优化:

          • 对于网络磁盘或涉及大量文件的操作, 尽量减少 I/O 操作以提高性能.
        • 跨平台注意事项:

          • 路径格式: 虽然 std::filesystem 自动处理不同平台的路径分隔符差异(Windows 使用 \, 其他平台使用 /), 但建议始终使用 fs::path 进行路径操作.
          • 文件权限: 不同平台的文件权限管理可能不一致, 尤其是 fs::permissions.
        • 路径组合:

          • 使用 / 操作符组合路径比直接字符串拼接更安全.
        • 路径规范化:

          • 使用 lexically_normal() 清理路径中的 . 和 .., 以获得更简洁的路径表示.

        限制性

        • 调用链接文件: 包含链接文件的操作在不同平台上有不同表现.
        • 性能: 尽管高效, 部分文件系统操作在网络磁盘上仍会突出慢.

        结论

        std::filesystem 库是 C++ 重要的增加, 使文件和目录操作更加简单和可移植. 无论您是在写一个简单脚本, 还是构建复杂应用, 熟练该库都是值得一试的.

        开始探索 std::filesystem, 你将发现它是你 C++ 程序装备中一个珍贵的工具!

        到此这篇关于C++17 Filesystem 实用教程的文章就介绍到这了,更多相关C++17 Filesystem内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜