C++文件路径处理4 - 根据软连接的路径获取真实路径&根据相对路径获取绝对路径
1. 关键词 C++ 文件路径处理 软连接 真实路径 相对路径 绝对路径 跨平台
2. filesystem.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 #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. 测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #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. 运行结果 1 2 3 4 5 6 7 8 9 10 ---------------------------------------TestRealpathAndAbspath--------------------------------------- symlink_path: ./fileutil_test/link4 realpath : /Users/spencer/workspace/common_util/fileutil_test/file4.dataabspath: /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。