1. 关键词
C++ 文件路径处理 软连接 真实路径 相对路径 绝对路径 跨平台
2. filesystem.h
| |
| #pragma once |
| |
| #include <string> |
| #include <iostream> |
| #include <cstdio> |
| #include "filetype.h" |
| |
| namespace cutl |
| { |
| |
| std::string file_readlink(const std::string &filepath); |
| |
| |
| std::string absolute_path(const std::string &releative_path); |
| |
| } |
3. filesystem_unix.cpp
| #if defined(_WIN32) || defined(__WIN32__) |
| |
| #else |
| |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <dirent.h> |
| #include <stack> |
| #include <cstring> |
| #include <utime.h> |
| #include <stdlib.h> |
| #include <sys/time.h> |
| #include "filesystem.h" |
| #include "inner/logger.h" |
| |
| namespace cutl |
| { |
| |
| std::string file_readlink(const std::string &filepath) |
| { |
| char buffer[MAX_PATH_LEN] = {0}; |
| ssize_t len = ::readlink(filepath.c_str(), buffer, MAX_PATH_LEN); |
| if (len < 0) |
| { |
| CUTL_ERROR("readlink error. filepath:" + filepath + ", error:" + strerror(errno)); |
| return ""; |
| } |
| return std::string(buffer, len); |
| } |
| |
| std::string absolute_path(const std::string &releative_path) |
| { |
| char absPath[PATH_MAX] = {0}; |
| auto pAbsolutePath = realpath(releative_path.c_str(), absPath); |
| if (pAbsolutePath == nullptr) |
| { |
| CUTL_WARN("realpath failure for " + releative_path + ", pAbsolutePath is nullptr, absPath:" + absPath); |
| return std::string(absPath); |
| } |
| |
| return std::string(absPath); |
| } |
| |
| } |
| |
| #endif |
4. filesystem_win.cpp
| #if defined(_WIN32) || defined(__WIN32__) |
| |
| #include <io.h> |
| #include <direct.h> |
| #include <Windows.h> |
| #include <stdlib.h> |
| #include "strutil.h" |
| #include "filesystem.h" |
| #include "logger.h" |
| |
| namespace cutl |
| { |
| std::string file_readlink(const std::string &filepath) |
| { |
| CUTL_ERROR("file_readlink() is not supported on Windows"); |
| return ""; |
| } |
| |
| std::string absolute_path(const std::string &releative_path) |
| { |
| char absPath[MAX_PATH_LEN] = {0}; |
| auto pAbsolutePath = _fullpath(absPath, releative_path.c_str(), MAX_PATH_LEN); |
| if (pAbsolutePath == nullptr) |
| { |
| CUTL_WARN("_fullpath failure, pAbsolutePath is nullptr"); |
| return std::string(absPath); |
| } |
| return std::string(absPath); |
| } |
| } |
| |
| #endif |
5. filepath.h
| |
| #pragma once |
| |
| #include <string> |
| #include <iostream> |
| #include <cstdio> |
| #include "filetype.h" |
| |
| namespace cutl |
| { |
| |
| |
| |
| |
| |
| class filepath |
| { |
| public: |
| |
| |
| |
| |
| |
| filepath(const std::string &path); |
| |
| |
| |
| |
| |
| |
| filepath(const filepath &other); |
| |
| |
| |
| |
| |
| |
| |
| filepath &operator=(const filepath &other); |
| |
| |
| |
| |
| |
| ~filepath() = default; |
| |
| public: |
| |
| |
| |
| |
| |
| |
| |
| std::string realpath() const; |
| |
| |
| |
| |
| |
| std::string abspath() const; |
| |
| private: |
| std::string filepath_; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| std::ostream &operator<<(std::ostream &os, const filepath &fp); |
| |
| |
| |
| |
| |
| |
| |
| filepath path(const std::string &path); |
| |
| } |
6. filepath.cpp
| |
| #include "filepath.h" |
| #include "inner/logger.h" |
| #include "inner/filesystem.h" |
| #include "strutil.h" |
| #include "sysutil.h" |
| |
| namespace cutl |
| { |
| static constexpr char win_separator = '\\'; |
| static constexpr char unix_separator = '/'; |
| |
| void fixpath(std::string &path) |
| { |
| if (win_separator == filepath::separator()) |
| { |
| for (size_t i = 0; i < path.size(); i++) |
| { |
| if (path[i] == unix_separator) |
| { |
| path[i] = win_separator; |
| } |
| } |
| } |
| else if (unix_separator == filepath::separator()) |
| { |
| for (size_t i = 0; i < path.size(); i++) |
| { |
| if (path[i] == win_separator) |
| { |
| path[i] = unix_separator; |
| } |
| } |
| } |
| else |
| { |
| |
| } |
| |
| while (path.empty() || path.back() == filepath::separator()) |
| { |
| path.pop_back(); |
| } |
| } |
| |
| filepath::filepath(const std::string &path) |
| { |
| filepath_ = path; |
| fixpath(filepath_); |
| } |
| |
| filepath::filepath(const filepath &other) |
| { |
| filepath_ = other.filepath_; |
| } |
| |
| filepath &filepath::operator=(const filepath &other) |
| { |
| this->filepath_ = other.filepath_; |
| return *this; |
| } |
| |
| char filepath::separator() |
| { |
| #if defined(_WIN32) || defined(__WIN32__) |
| return win_separator; |
| #else |
| return unix_separator; |
| #endif |
| } |
| |
| std::string filepath::str() const |
| { |
| return filepath_; |
| } |
| |
| filepath filepath::join(const std::string &filename) const |
| { |
| std::string path = filepath_ + separator() + filename; |
| return filepath(path); |
| } |
| |
| std::string filepath::realpath() const |
| { |
| if (issymlink()) |
| { |
| return file_readlink(filepath_); |
| } |
| |
| CUTL_ERROR("not a symlink, cannot get realpath"); |
| return ""; |
| } |
| |
| std::string filepath::abspath() const |
| { |
| auto filepath = filepath_; |
| if (starts_with(filepath_, "~")) |
| { |
| |
| filepath = homedir() + filepath_.substr(1); |
| } |
| return absolute_path(filepath); |
| } |
| |
| std::ostream &operator<<(std::ostream &os, const filepath &fp) |
| { |
| os << fp.str(); |
| return os; |
| } |
| |
| filepath path(const std::string &path) |
| { |
| return filepath(path); |
| } |
| } |
7. 测试代码
| #include "common.hpp" |
| #include "fileutil.h" |
| |
| void TestRealpathAndAbspath() |
| { |
| PrintSubTitle("TestRealpathAndAbspath"); |
| |
| auto symlink_path = cutl::path("./fileutil_test/link4"); |
| std::cout << "symlink_path: " << symlink_path << std::endl; |
| std::cout << "realpath: " << symlink_path.realpath() << std::endl; |
| std::cout << "abspath: " << symlink_path.abspath() << std::endl; |
| |
| auto path1 = cutl::path("../common_util/fileutil_test/file4.data"); |
| std::cout << "path1 abspath: " << path1.abspath() |
| << ", exists: " << path1.exists() << std::endl; |
| |
| auto path2 = cutl::path("./fileutil_test/file4.data"); |
| std::cout << "path2 abspath: " << path2.abspath() |
| << ", exists: " << path2.exists() << std::endl; |
| |
| auto path3 = cutl::path("./fileutil_test/../../common_util/fileutil_test/file4.data"); |
| std::cout << "path3 abspath: " << path3.abspath() |
| << ", exists: " << path3.exists() << std::endl; |
| |
| auto path4 = cutl::path("./fileutil_test/../../common_util/fileutil_test/file_xx.data"); |
| std::cout << "path4 abspath: " << path4.abspath() |
| << ", exists: " << path4.exists() << std::endl; |
| |
| auto path5 = cutl::path("~/workspace/common_util/fileutil_test/file4.data"); |
| std::cout << "path5 abspath: " << path5.abspath() |
| << ", exists: " << path5.exists() << std::endl; |
| } |
8. 运行结果
| ---------------------------------------TestRealpathAndAbspath--------------------------------------- |
| symlink_path: ./fileutil_test/link4 |
| realpath: /Users/spencer/workspace/common_util/fileutil_test/file4.data |
| abspath: /Users/spencer/workspace/common_util/fileutil_test/file4.data |
| path1 abspath: /Users/spencer/workspace/common_util/fileutil_test/file4.data, exists: 1 |
| path2 abspath: /Users/spencer/workspace/common_util/fileutil_test/file4.data, exists: 1 |
| path3 abspath: /Users/spencer/workspace/common_util/fileutil_test/file4.data, exists: 1 |
| path4 abspath: [2024-06-26 12:25:45.877][W]]0x7ff85b8d5fc0](cutl) [filesystem_unix.cpp:46:absolute_path] realpath failure for ./fileutil_test/../../common_util/fileutil_test/file_xx.data, pAbsolutePath is nullptr, absPath:/Users/spencer/workspace/common_util/fileutil_test/file_xx.data |
| /Users/spencer/workspace/common_util/fileutil_test/file_xx.data, exists: 0 |
| |
9. 源码地址
更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战