file.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /*Software License
  2. Copyright(C) 2024[liuyingjie]
  3. License Terms
  4. Usage Rights
  5. Any individual or entity is free to use, copy, and distribute the binary form of this software without modification to the source code, without the need to disclose the source code.
  6. If the source code is modified, the modifications must be open - sourced under the same license.This means that the modifications must be disclosed and accompanied by a copy of this license.
  7. Future Versions Updates
  8. From this version onwards, all future releases will be governed by the terms of the latest version of the license.This license will automatically be nullified and replaced by the new version.
  9. Users must comply with the terms of the new license issued in future releases.
  10. Liability and Disclaimer
  11. This software is provided “as is”, without any express or implied warranties, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non - infringement.In no event shall the author or copyright holder be liable for any claims, damages, or other liabilities, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
  12. Contact Information
  13. If you have any questions, please contact us: 1585346868@qq.com Or visit our website fwlua.com.
  14. */
  15. #include "util/file.h"
  16. #include <cstdio>
  17. #include <filesystem>
  18. #include <regex>
  19. #ifdef _WIN32
  20. #include <io.h>
  21. #include <Windows.h>
  22. #else
  23. #include <dirent.h>
  24. #include <sys/stat.h>
  25. #endif
  26. #include "util/strutils.h"
  27. #include "util/system.h"
  28. bool ylib::file::remove(const std::string &filepath)
  29. {
  30. return std::remove(filepath.c_str()) == 0;
  31. }
  32. bool ylib::file::create_dir(const std::string &dirpath,bool create_parent_dir)
  33. {
  34. if (dirpath.empty())
  35. return false;
  36. std::filesystem::path path = dirpath;
  37. while(!create_parent_dir){
  38. auto parent = path.parent_path();
  39. if(parent.empty())
  40. break;
  41. if(std::filesystem::exists(parent) == false)
  42. return false;
  43. }
  44. try
  45. {
  46. return std::filesystem::create_directories(std::filesystem::path(dirpath));
  47. }
  48. catch(const std::exception& e)
  49. {
  50. std::cout << e.what() <<"\tfilepath:"<< dirpath<<" create_parent_dir:"<< create_parent_dir << std::endl;
  51. }
  52. return false;
  53. }
  54. ylib::file_io::file_io()
  55. {
  56. }
  57. ylib::file_io::~file_io()
  58. {
  59. close();
  60. }
  61. bool ylib::file_io::open(const std::string &filepath,bool only_read, bool auto_create)
  62. {
  63. close();
  64. std::ios_base::openmode openmode = std::ios::in|std::ios::binary;
  65. if(!only_read)
  66. openmode |= std::ios::out;
  67. m_stream = new std::fstream(filepath,openmode);
  68. if(!m_stream->is_open()){
  69. if(only_read)
  70. {
  71. close();
  72. return false;
  73. }
  74. // 尝试创建文件,如果不存在的话
  75. std::ofstream outfile(filepath, std::ios::binary);
  76. outfile.close();
  77. // 再次尝试打开文件
  78. m_stream->open(filepath, std::ios::in | std::ios::out | std::ios::binary | std::ios::app);
  79. if (!m_stream->is_open()) {
  80. m_lastErrorDesc = "Failed to open or create file: " + filepath;
  81. close();
  82. return false;
  83. }
  84. }
  85. m_only_read = only_read;
  86. m_filepath = filepath;
  87. return true;
  88. }
  89. void ylib::file_io::close()
  90. {
  91. if(m_stream != nullptr){
  92. m_stream->close();
  93. delete m_stream;
  94. m_stream = nullptr;
  95. }
  96. m_filepath.clear();
  97. m_only_read = false;
  98. }
  99. bool ylib::file_io::appead(const char *data, int64 len)
  100. {
  101. jump(0,std::ios::end);
  102. return write(data,len);
  103. }
  104. bool ylib::file_io::appead(const buffer &data)
  105. {
  106. return appead(data.data(),data.length());
  107. }
  108. bool ylib::file_io::write(const char *data, int64 len)
  109. {
  110. if(data == nullptr || len == 0)
  111. return true;
  112. m_stream->write(data,len);
  113. if(m_stream->fail())
  114. {
  115. m_lastErrorDesc = "write operation failed.";
  116. return false;
  117. }
  118. m_stream->flush();
  119. if(m_stream->fail())
  120. {
  121. m_lastErrorDesc = "flush operation failed.";
  122. return false;
  123. }
  124. return true;
  125. }
  126. bool ylib::file_io::write(const ylib::buffer &data)
  127. {
  128. return write(data.data(),data.length());
  129. }
  130. ylib::buffer ylib::file_io::read(int64 size)
  131. {
  132. ylib::buffer result;
  133. read(size,result);
  134. return result;
  135. }
  136. bool ylib::file_io::read(int64 size, buffer &data)
  137. {
  138. if (size == 0)
  139. return false;
  140. data.resize((size_t)size);
  141. m_stream->read((char*)data.data(),size);
  142. if(m_stream->fail())
  143. {
  144. data.clear();
  145. m_lastErrorDesc ="read failed,size:"+std::to_string(size);
  146. return false;
  147. }
  148. return true;
  149. }
  150. void ylib::file_io::jump(int64 offset, std::ios_base::seekdir way)
  151. {
  152. // 清楚所有错误状态
  153. m_stream->clear();
  154. // 根据提供的方向参数way来确定如何应用偏移量offset
  155. if (way == std::ios::beg || way == std::ios::end) {
  156. // 如果参考点是文件的开头或结尾,直接应用偏移量
  157. m_stream->seekg(offset, way); // seekg是用来设置istream(输入流)的位置的。
  158. m_stream->seekp(offset, way); // seekp是用来设置ostream(输出流)的位置的。
  159. } else if (way == std::ios::cur) {
  160. // 如果参考点是当前位置,由于当前读位置和写位置可能不同,需要分别设置
  161. std::streampos currentPosition = m_stream->tellg(); // 获取当前读位置
  162. m_stream->seekg(currentPosition + offset, std::ios::beg); // 将读位置移动offset个单位
  163. currentPosition = m_stream->tellp(); // 获取当前写位置
  164. m_stream->seekp(currentPosition + offset, std::ios::beg); // 将写位置移动offset个单位
  165. }
  166. // 注意: 如果流是用于同时读写的,那么我们需要保持读取和写入指针同步。
  167. // 在某些情况下,你可能只需要移动读指针或写指针,这取决于你的用例。
  168. }
  169. std::streampos ylib::file_io::cur()
  170. {
  171. return m_stream->tellg();
  172. }
  173. bool ylib::file_io::clear()
  174. {
  175. if(m_only_read){
  176. throw ylib::exception("The file is read-only and cannot be clear");
  177. return false;
  178. }
  179. m_stream->close();
  180. m_stream->open(m_filepath, std::ios::out | std::ios::trunc | std::ios::binary);
  181. m_stream->close();
  182. m_stream->open(m_filepath, std::ios::in | std::ios::out | std::ios::ate | std::ios::binary);
  183. return true;
  184. }
  185. std::streamsize ylib::file_io::size()
  186. {
  187. auto cur_pos = cur();
  188. jump(0,std::ios::end);
  189. auto result = m_stream->tellg();
  190. jump(cur_pos,std::ios::beg);
  191. return result;
  192. }
  193. bool file_io::is_open()
  194. {
  195. return m_stream->is_open();
  196. }
  197. ylib::buffer ylib::file::read(const std::string &filepath)
  198. {
  199. ylib::file_io f;
  200. if(!f.open(filepath,true))
  201. return ylib::buffer();
  202. return f.read(f.size());
  203. }
  204. bool file::read(const std::string &filepath, buffer &data)
  205. {
  206. ylib::file_io f;
  207. if(!f.open(filepath,true))
  208. return false;
  209. data = f.read(f.size());
  210. return true;
  211. }
  212. bool ylib::file::write(const std::string &filepath, const buffer &data)
  213. {
  214. return write(filepath,data.data(),data.length());
  215. }
  216. bool ylib::file::write(const std::string &filepath, const char *data, size_t len)
  217. {
  218. ylib::file_io f;
  219. if(!f.open(filepath))
  220. return false;
  221. f.clear();
  222. return f.write(data,len);
  223. }
  224. bool ylib::file::list(const std::string &rootPath, std::map<std::string, bool> &list)
  225. {
  226. list.clear();
  227. #ifdef _WIN32
  228. char dirNew[200];
  229. strcpy_s(dirNew, rootPath.c_str());
  230. strcat_s(dirNew, "\\*.*");
  231. intptr_t handle;
  232. _finddata_t findData;
  233. handle = _findfirst(dirNew, &findData); // 查找目录中的第一个文件
  234. if (handle == -1)
  235. {
  236. list.insert(std::make_pair(rootPath,false));
  237. }
  238. else
  239. {
  240. do
  241. {
  242. list.insert(std::make_pair(findData.name, GetFileAttributesA(std::string(rootPath + "\\" + findData.name).c_str()) & FILE_ATTRIBUTE_DIRECTORY));
  243. } while (_findnext(handle, &findData) == 0); // 查找目录中的下一个文件
  244. }
  245. _findclose(handle); // 关闭搜索句柄
  246. return true;
  247. #else
  248. DIR* dir;
  249. struct dirent* entry;
  250. struct stat info;
  251. if ((dir = opendir(rootPath.c_str())) == NULL)
  252. {
  253. list.insert(std::make_pair(rootPath, false));
  254. return false;
  255. }
  256. while ((entry = readdir(dir)) != NULL)
  257. {
  258. std::string fullPath = rootPath + "/" + entry->d_name;
  259. if (stat(fullPath.c_str(), &info) != 0)
  260. {
  261. list.insert(std::make_pair(entry->d_name, false));
  262. }
  263. else
  264. {
  265. bool isDirectory = S_ISDIR(info.st_mode);
  266. list.insert(std::make_pair(entry->d_name, isDirectory));
  267. }
  268. }
  269. closedir(dir);
  270. return true;
  271. #endif // _WIN32
  272. }
  273. bool ylib::file::remove_dir(const std::string &dirpath
  274. #if _WIN32
  275. , bool recycle
  276. #endif
  277. )
  278. {
  279. #if _WIN32
  280. if (recycle)
  281. {
  282. SHFILEOPSTRUCT shDelFile;
  283. memset(&shDelFile, 0, sizeof(SHFILEOPSTRUCT));
  284. shDelFile.fFlags |= FOF_SILENT;
  285. shDelFile.fFlags |= FOF_NOERRORUI;
  286. shDelFile.fFlags |= FOF_NOCONFIRMATION;
  287. shDelFile.wFunc = FO_DELETE;
  288. ylib::buffer path;
  289. path.append(dirpath);
  290. path.append('\0');
  291. path.append('\0');
  292. shDelFile.pFrom = (LPCSTR)path.data();
  293. shDelFile.pTo = NULL;
  294. shDelFile.fFlags |= FOF_ALLOWUNDO;
  295. BOOL bres = SHFileOperation(&shDelFile);
  296. return !bres;
  297. }
  298. #endif
  299. try {
  300. // 删除指定的目录及其所有内容
  301. std::uintmax_t n = std::filesystem::remove_all(dirpath);
  302. } catch (const std::filesystem::filesystem_error& e) {
  303. std::cout << "remove_dir failed,error:" + std::string(e.what()) + ",dirpath:" + dirpath << std::endl;
  304. return false;
  305. }
  306. return true;
  307. }
  308. std::string ylib::file::ext(const std::string &path)
  309. {
  310. // 查找最后一个点的位置
  311. std::size_t last_dot_pos = path.find_last_of(".");
  312. // 检查是否有扩展名并返回
  313. if (last_dot_pos != std::string::npos && last_dot_pos != path.length() - 1)
  314. return path.substr(last_dot_pos + 1);
  315. // 没有扩展名或点在末尾
  316. return "";
  317. }
  318. bool ylib::file::exist(const std::string &filepath)
  319. {
  320. try
  321. {
  322. return std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath);
  323. }
  324. catch (const std::exception& e)
  325. {
  326. std::cout << e.what() << std::endl;
  327. }
  328. return false;
  329. }
  330. bool ylib::file::exist_dir(const std::string& dirpath)
  331. {
  332. try
  333. {
  334. return std::filesystem::exists(dirpath) && std::filesystem::is_directory(dirpath);
  335. }
  336. catch (const std::exception& e)
  337. {
  338. std::cout << e.what() << std::endl;
  339. }
  340. return false;
  341. }
  342. int64 ylib::file::size(const std::string &filepath)
  343. {
  344. try
  345. {
  346. std::filesystem::path file_path(filepath);
  347. if (std::filesystem::exists(file_path)) {
  348. return std::filesystem::file_size(file_path);
  349. }
  350. else {
  351. return 0;
  352. }
  353. }
  354. catch (const std::exception& e)
  355. {
  356. std::cout << "ylib::file::size exception: " << e.what() <<"\tpath: "<< filepath << std::endl;
  357. return 0;
  358. }
  359. }
  360. std::string ylib::file::parent_dir(const std::string &path)
  361. {
  362. std::filesystem::path file_path(path);
  363. return file_path.parent_path().string();
  364. }
  365. std::string ylib::file::filename(const std::string& path, bool have_ext)
  366. {
  367. std::filesystem::path fsPath(path);
  368. std::string fileName = fsPath.filename().string();
  369. if (!have_ext) {
  370. fileName = fsPath.stem().string();
  371. }
  372. return fileName;
  373. }
  374. bool ylib::file::copy(const std::string& src, const std::string& dst)
  375. {
  376. try {
  377. #ifdef _WIN32
  378. return CopyFileA(src.c_str(),dst.c_str(),false);
  379. #else
  380. // 复制文件
  381. std::filesystem::copy(src, dst, std::filesystem::copy_options::overwrite_existing);
  382. #endif
  383. return true;
  384. }
  385. catch (const std::exception& e) {
  386. std::cout << "copy exception, src:" << src << "\tdst:" << dst << ". error:" << e.what() << std::endl;
  387. }
  388. return false;
  389. }
  390. void ylib::file::copy_dir(const std::string& src, const std::string& dst)
  391. {
  392. ylib::file::create_dir(dst, true);
  393. auto map = traverse(src,".*");
  394. for_iter(iter, map) {
  395. if (iter->second == IS_DIRECTORY)
  396. ylib::file::create_dir(dst+"/"+iter->first,true);
  397. }
  398. for_iter(iter, map) {
  399. if (iter->second == IS_FILE)
  400. ylib::file::copy(src+"/" + iter->first, dst + "/" + iter->first);
  401. }
  402. }
  403. std::map<std::string, ylib::FileType> ylib::file::traverse(const std::string& dirpath, const std::string& regex_pattern)
  404. {
  405. std::map<std::string, ylib::FileType> files_and_directories;
  406. std::regex pattern(regex_pattern); // 创建正则表达式对象
  407. if (!std::filesystem::exists(dirpath) || !std::filesystem::is_directory(dirpath)) {
  408. std::cerr << "provided path is not a valid directory. dir:"<<dirpath << std::endl;
  409. return files_and_directories;
  410. }
  411. try {
  412. for (const auto& entry : std::filesystem::recursive_directory_iterator(dirpath)) {
  413. const auto& path = entry.path();
  414. // 检查是否是文件且符合正则表达式
  415. std::string path_string = strutils::right(path.string(), path.string().length() - dirpath.length());
  416. path_string =strutils::trim_begin(path_string, { '\\','/'});
  417. if (entry.is_regular_file() && std::regex_match(path.filename().string(), pattern)) {
  418. files_and_directories[path_string] = ylib::FileType::IS_FILE;
  419. }
  420. else if (entry.is_directory())
  421. {
  422. files_and_directories[path_string] = ylib::FileType::IS_DIRECTORY;
  423. }
  424. }
  425. }
  426. catch (const std::exception& e) {
  427. std::cerr << "error occurred: " << e.what() << std::endl;
  428. }
  429. return files_and_directories;
  430. }
  431. std::string ylib::file::temp_filepath()
  432. {
  433. return system::temp_path() + SEPRATOR + std::to_string(system::random(99999999,999999999));
  434. }
  435. std::string ylib::file::format_separator(const std::string& filepath)
  436. {
  437. std::string result = filepath;
  438. for (size_t i = 0; i < result.size(); i++)
  439. {
  440. #ifdef _WIN32
  441. if (result[i] == '/')
  442. result[i] = '\\';
  443. #else
  444. if (result[i] == '\\')
  445. result[i] = '/';
  446. #endif
  447. }
  448. return result;
  449. }
  450. timestamp ylib::file::last_write_time(const std::string& filepath)
  451. {
  452. try {
  453. // 获取文件最后修改时间
  454. auto ftime = std::filesystem::last_write_time(filepath);
  455. auto sctp = std::chrono::time_point_cast<std::chrono::seconds>(ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
  456. auto time_since_epoch = sctp.time_since_epoch();
  457. auto seconds = std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count();
  458. return seconds;
  459. }
  460. catch (const std::filesystem::filesystem_error& e) {
  461. std::cerr << e.what() << std::endl;
  462. return -1;
  463. }
  464. return -1;
  465. }