file.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * 文件名: file.c
  3. * 目标: 关于文件读取的实用函数
  4. */
  5. #include <sys/stat.h>
  6. #include <cctype>
  7. #include <cstdio>
  8. #include <cstdlib>
  9. #include "tool-type.h"
  10. #include "file.h"
  11. #include "path.h"
  12. #include "str.h"
  13. #include "log.h"
  14. #include "tool-stdio.h"
  15. #ifdef aFunWIN32_NO_CYGWIN
  16. #ifdef _MSC_VER
  17. #pragma warning(disable : 5105) // 关闭 5105 的警告输出 (Windows.h中使用)
  18. #endif
  19. #include <Windows.h>
  20. #else
  21. #include <unistd.h>
  22. #endif
  23. #ifndef S_ISREG
  24. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  25. #endif
  26. #ifndef S_ISDIR
  27. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  28. #endif
  29. namespace aFuntool {
  30. #ifdef aFunWIN32_NO_CYGWIN
  31. typedef struct _stat64 aFun_stat;
  32. typedef wchar_t aFun_path;
  33. #else
  34. typedef struct stat aFun_stat;
  35. typedef char aFun_path;
  36. #endif
  37. /**
  38. * 获取文件的stat结构体
  39. * @param stat stat 保存地址
  40. * @param path 路径 (utf-8)
  41. * @return
  42. */
  43. static int get_stat(aFun_stat &stat_, const std::string &path_){
  44. int re;
  45. #ifdef aFunWIN32_NO_CYGWIN
  46. aFun_path *tmp = nullptr;
  47. if (convertWideByte(&tmp, path_.c_str(), CP_UTF8) == 0)
  48. return -1;
  49. re = _wstat64(tmp, &stat_);
  50. safeFree(tmp); // 如果 path 为nullptr, 则释放最新生成的 wchat_t
  51. #else
  52. re = stat(path_.c_str(), &stat_);
  53. #endif
  54. return re;
  55. }
  56. /**
  57. * 目标判断文件类型, 若是普通文件返回1, 若是文件夹返回2, 其他遇到错误返回0
  58. */
  59. int checkFile(const std::string &path){
  60. if (path.empty())
  61. return 0;
  62. int re = 0;
  63. aFun_stat stat;
  64. if (get_stat(stat, path) != 0)
  65. re = 0;
  66. else if (S_ISREG(stat.st_mode)) // 普通文件
  67. re = 1;
  68. else if (S_ISDIR(stat.st_mode))
  69. re = 2;
  70. return re;
  71. }
  72. /**
  73. * 获取文件最后修改时间
  74. */
  75. time_t getFileMTime(const std::string &path) {
  76. aFun_stat stat;
  77. if (path.empty() || get_stat(stat, path) != 0)
  78. return 0;
  79. return stat.st_mtime;
  80. }
  81. /**
  82. * 拼接路径
  83. * @param path 路径
  84. * @param name 文件名
  85. * @param suffix 后缀
  86. * @return
  87. */
  88. std::string joinPath(const std::string &path, const std::string &name, const std::string &suffix) {
  89. std::string name_suffix = name + suffix;
  90. if (!path.empty() && *(path.end()) == SEP_CH)
  91. return path + name_suffix;
  92. else if (!path.empty())
  93. return path + SEP + name_suffix;
  94. return name_suffix;
  95. }
  96. /**
  97. * 给定路径获取该路径所指定的文件名
  98. */
  99. std::string getFileName(const std::string &path){
  100. int sep = 0;
  101. if (*(path.end()) == SEP_CH) // 若路径的最后一个字符为SEP, 则忽略此SEP
  102. sep = -1;
  103. auto slash = path.find_last_of('/');
  104. if (slash == std::string::npos)
  105. slash = 0;
  106. else
  107. slash++;
  108. return path.substr(path.size() - slash + sep, slash);
  109. }
  110. /**
  111. * 获取 文件路径+文件名(排除后缀)
  112. */
  113. std::string getFilePathName(const std::string &path){
  114. auto point = path.find_last_of('.');
  115. if (point == std::string::npos)
  116. return path;
  117. return path.substr(point);
  118. }
  119. /**
  120. * 获取文件路径(不包含文件名)
  121. */
  122. std::string getFilePath(const std::string &path, int dep){
  123. std::string::size_type point = path.size();
  124. for (int i = 0; i < dep; i++) {
  125. auto tmp = path.rfind(SEP_CH, point - 1);
  126. if (tmp == std::string::npos)
  127. break;
  128. point = tmp;
  129. }
  130. return path.substr(0, point);
  131. }
  132. /**
  133. * 获取文件后缀
  134. */
  135. std::string getFileSurfix(const std::string &path) {
  136. auto point = path.find_last_of('.');
  137. if (point == std::string::npos)
  138. point = 0;
  139. else
  140. point++;
  141. std::string ret = path.substr(path.size() - point, point);
  142. return ret;
  143. }
  144. /**
  145. * 把一个文件名转换为合法的变量名(替换不合法字符为_)
  146. * @param name 路径
  147. * @param need_free 是否需要释放
  148. */
  149. std::string fileNameToVar(const std::string &name){
  150. char *var = strCopy(name.c_str()); // 复制新的数据再修改
  151. if (!isalpha(*var) && *var != '_')
  152. var = strJoin("_", var, false, true);
  153. for (char *tmp = var; *tmp != 0; tmp++)
  154. if (!isalnum(*tmp) &&'_' != *tmp)
  155. *tmp = '_';
  156. std::string ret = var;
  157. safeFree(var);
  158. return ret;
  159. }
  160. /**
  161. * 转换路径为合法路径(相对路径->绝对路径, 绝对路径保持不变)
  162. * @param path 文件路径
  163. * @param env 环境 必须以 / 结尾
  164. * @param need_free 是否需要释放 path
  165. */
  166. std::string findPath(const std::string &path, const std::string &env){
  167. #ifdef __linux
  168. if (path[0] != SEP_CH) // 不以 / 开头
  169. #else
  170. if (!(isupper(path[0]) && (path)[1] == ':')) // 不以盘符开头
  171. #endif
  172. return env + path; // 调整为相对路径模式
  173. return path;
  174. }
  175. /**
  176. * 获取可执行程序目录
  177. * @param dep 从可执行程序往回跳出的层数
  178. */
  179. std::string getHomePath() {
  180. aFun_path exe_path[218] = {0};
  181. #ifdef aFunWIN32_NO_CYGWIN
  182. DWORD ret = GetModuleFileNameW(nullptr, exe_path, 217); // 预留一位给NUL
  183. if (ret == 0 || wcslen(exe_path) == 0)
  184. return "";
  185. char *path = nullptr;
  186. if (convertFromWideByte(&path, exe_path, CP_UTF8) == 0)
  187. return "";
  188. std::string re = getFilePath(path, 2);
  189. safeFree(path);
  190. return re;
  191. #else
  192. ssize_t ret = readlink("/proc/self/exe", exe_path, 217); // 预留一位给NUL
  193. if (ret == -1 || strlen(exe_path) == 0)
  194. return "";
  195. return getFilePath(exe_path, 2);
  196. #endif
  197. }
  198. /**
  199. * 获取可执行程序目录
  200. * @param dep 从可执行程序往回跳出的层数
  201. */
  202. std::string getExePath() {
  203. aFun_path exe_path[218] = {0};
  204. #ifdef aFunWIN32_NO_CYGWIN
  205. DWORD ret = GetModuleFileNameW(nullptr, exe_path, 217); // 预留一位给NUL
  206. if (ret == 0 || wcslen(exe_path) == 0)
  207. return "";
  208. char *path = nullptr;
  209. if (convertFromWideByte(&path, exe_path, CP_UTF8) == 0)
  210. return "";
  211. std::string re = path;
  212. safeFree(path);
  213. return re;
  214. #else
  215. ssize_t ret = readlink("/proc/self/exe", exe_path, 217); // 预留一位给NUL
  216. if (ret == -1 || strlen(exe_path) == 0)
  217. return "";
  218. return exe_path;
  219. #endif
  220. }
  221. /**
  222. * @param path 文件路径 (utf-8)
  223. * @return 文件大小
  224. */
  225. uintmax_t getFileSize(const std::string &path) {
  226. aFun_stat stat;
  227. int ret;
  228. ret = get_stat(stat, path);
  229. if(ret != 0)
  230. return 0; // 获取失败。
  231. return (uintmax_t)stat.st_size; // 返回文件大小
  232. }
  233. /**
  234. * 检查给定字符串是否utf-8编码
  235. * @param str 字符串
  236. */
  237. bool isCharUTF8(const char *str) {
  238. int code = 0; // utf-8 多字节数
  239. for (const char *ch = str; *ch != NUL; ch++) {
  240. unsigned char c = *ch;
  241. unsigned char c_ = ~c;
  242. assertFatalErrorLog(code >= 0 && code <= 5, aFunSysLogger, 2, "str = %s", str);
  243. if (code == 0) {
  244. if ((c_ & 0xFC) == 0 && (c & 0x02) == 0) // 检查是否为1111110x, 先对其取反, 使用0xFC掩码检查前6位是否为0, 然后单独检查倒数第二位是否为0
  245. code = 5; // 剩余 5 个字节
  246. else if ((c_ & 0xF8) == 0 && (c & 0x04) == 0)
  247. code = 4; // 剩余 4 个字节
  248. else if ((c_ & 0xF0) == 0 && (c & 0x08) == 0)
  249. code = 3; // 剩余 3 个字节
  250. else if ((c_ & 0xE0) == 0 && (c & 0x10) == 0)
  251. code = 2; // 剩余 2 个字节
  252. else if ((c_ & 0xC0) == 0 && (c & 0x20) == 0)
  253. code = 1; // 剩余 1 个字节
  254. else if ((c & 0x80) == 0) // 检查最高位是否为0
  255. code = 0;
  256. else
  257. return false;
  258. } else if ((c_ & 0x80) == 0 && (c & 0x40) == 0)
  259. code--;
  260. else
  261. return false;
  262. }
  263. return true;
  264. }
  265. bool isCharUTF8(const std::string &str) {
  266. return isCharUTF8(str.c_str());
  267. }
  268. /**
  269. * 打开指定文件
  270. * @param path_ 路径 (utf-8)
  271. * @param mode_ 模式
  272. * @return
  273. */
  274. FILE *fileOpen(const char *path_, const char *mode_) {
  275. if (strlen(mode_) >= 5)
  276. return nullptr;
  277. #ifdef aFunWIN32_NO_CYGWIN
  278. FILE *file = nullptr;
  279. wchar_t *path = nullptr;
  280. wchar_t mode[5];
  281. if (convertWideByte(&path, path_, CP_UTF8) == 0)
  282. return nullptr;
  283. for (int i = 0; i < 5; i++)
  284. mode[i] = (wchar_t)mode_[i]; // ascii字符转换
  285. _wfopen_s(&file, path, mode);
  286. safeFree(path);
  287. return file;
  288. #else
  289. return fopen(path_, mode_);
  290. #endif
  291. }
  292. FILE *fileOpen(const std::string &path_, const char *mode_) {
  293. return fileOpen(path_.c_str(), mode_);
  294. }
  295. /**
  296. * 关闭文件, 本质和fclose一样
  297. * @param file FILE
  298. * @return
  299. */
  300. int fileClose(FILE *file) {
  301. return fclose(file);
  302. }
  303. }