DataStorageMgmt.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. #include "DataStorageMgmt.hpp"
  2. #include <ctime>
  3. #include <memepp/convert/common_def.hpp>
  4. #include <memepp/convert/std/string.hpp>
  5. #include <memepp/convert/std/wstring.hpp>
  6. #include <memepp/convert/self.hpp>
  7. #include <chrono>
  8. #include <mego/util/std/time.h>
  9. using namespace std;
  10. namespace ghcfs = ghc::filesystem;
  11. #define HISDATA_SAVE_MAX_DAYS 24 * 30 * 3 //3个月
  12. #define OFFLINE_DATA_SAVE_MAX_DAYS 24 * 7 //7天
  13. //获取当前日期字符串yyyyMMdd
  14. static memepp::string get_date_string()
  15. {
  16. struct tm timeinfo;
  17. mgu_time_t now = time(nullptr);
  18. mgu_localtime_s(&now, &timeinfo);
  19. char buffer[20];
  20. auto size = strftime(buffer, sizeof(buffer), "%Y%m%d", &timeinfo);
  21. return memepp::string(buffer, size);
  22. }
  23. //获取当前日期字符串yyyyMMddHH
  24. static memepp::string get_datetime_string()
  25. {
  26. struct tm timeinfo;
  27. mgu_time_t now = time(nullptr);
  28. mgu_localtime_s(&now,&timeinfo);
  29. char buffer[20];
  30. auto size = strftime(buffer, sizeof(buffer), "%Y%m%d%H", &timeinfo);
  31. return memepp::string(buffer, size);
  32. }
  33. //获取时间最早的文件
  34. memepp::native_string DataStorageMgmt::get_earliest_file(memepp::native_string folderPath)
  35. {
  36. ghcfs::path path(folderPath);
  37. std::string strEarliestFile = "";
  38. if (ghcfs::exists(folderPath) && ghcfs::is_directory(folderPath))
  39. {
  40. ghcfs::file_time_type earliestTime = ghcfs::file_time_type::time_point::max();
  41. for (const auto& entry : ghcfs::directory_iterator(folderPath))
  42. {
  43. if (ghcfs::is_regular_file(entry))
  44. {
  45. const auto createTime = ghcfs::last_write_time(entry);
  46. if (createTime < earliestTime)
  47. {
  48. earliestTime = createTime;
  49. strEarliestFile = entry.path().string();
  50. }
  51. }
  52. }
  53. }
  54. memepp::string mmpStr = memepp::string(strEarliestFile.c_str(), strEarliestFile.length());
  55. return mm_to<memepp::native_string>(mmpStr);
  56. }
  57. //获取时间最晚文件的文件名
  58. std::string DataStorageMgmt::get_last_filename(memepp::native_string folderPath)
  59. {
  60. ghcfs::path path(folderPath);
  61. std::string strLastFileName = "";
  62. if (ghcfs::exists(folderPath) && ghcfs::is_directory(folderPath))
  63. {
  64. ghcfs::file_time_type lastTime = ghcfs::file_time_type::time_point::min();
  65. for (const auto& entry : ghcfs::directory_iterator(folderPath))
  66. {
  67. if (ghcfs::is_regular_file(entry))
  68. {
  69. const auto createTime = ghcfs::last_write_time(entry);
  70. if (createTime > lastTime)
  71. {
  72. lastTime = createTime;
  73. strLastFileName = entry.path().filename().string();
  74. }
  75. }
  76. }
  77. }
  78. size_t pos = strLastFileName.rfind('.');
  79. if (pos != std::string::npos) {
  80. strLastFileName.erase(pos);
  81. }
  82. return strLastFileName;
  83. }
  84. DataStorageMgmt::DataStorageMgmt()
  85. {
  86. isCanSave = true;
  87. }
  88. DataStorageMgmt::~DataStorageMgmt()
  89. {
  90. //程序退出前,关闭文件句柄
  91. if (m_history_data_fs.is_open()) {
  92. m_history_data_fs.close();
  93. }
  94. if (m_offline_file_fs.is_open()) {
  95. m_offline_file_fs.close();
  96. }
  97. }
  98. void DataStorageMgmt::init_data_storage(memepp::native_string& folderPath, const uint8_t deviceId)
  99. {
  100. m_folderPath = folderPath;
  101. memepp::native_string strDate = mm_to<memepp::native_string>(get_date_string());
  102. #if MG_OS__WIN_AVAIL
  103. m_history_folder = folderPath + L"/HistoryData";
  104. m_history_folder_today = m_history_folder + L"/" + strDate;
  105. m_offline_folder = folderPath + L"/OfflineData";
  106. m_offline_folder_today = m_offline_folder + L"/" + strDate;
  107. #else
  108. m_history_folder = folderPath + "/HistoryData";
  109. m_history_folder_today = m_history_folder + "/" + strDate;
  110. m_offline_folder = folderPath + "/OffilneData";
  111. m_offline_folder_today = m_offline_folder + "/" + strDate;
  112. #endif
  113. // 如果历史数据文件夹不存在则进行创建
  114. if (!ghcfs::exists(m_history_folder))
  115. {
  116. ghcfs::create_directory(m_history_folder);
  117. }
  118. //每天一个文件夹,以年月日作为文件夹名
  119. if (!ghcfs::exists(m_history_folder_today))
  120. {
  121. ghcfs::create_directory(m_history_folder_today);
  122. }
  123. //如果离线数据文件夹不存在则进行创建
  124. if (!ghcfs::exists(m_offline_folder))
  125. {
  126. ghcfs::create_directory(m_offline_folder);
  127. }
  128. //如果离线数据文件夹不存在则进行创建
  129. if (!ghcfs::exists(m_offline_folder_today))
  130. {
  131. ghcfs::create_directory(m_offline_folder_today);
  132. }
  133. else
  134. {
  135. auto strTmp = get_last_filename(m_offline_folder_today);
  136. m_strDateTime = mm_to<memepp::native_string>(memepp::string(strTmp.c_str(), strTmp.length()));
  137. if (!m_strDateTime.empty())
  138. {
  139. size_t index = m_strDateTime.find('_'); // 查找下划线的位置
  140. if (index != std::string::npos)
  141. {
  142. std::string afterUnderscore = strTmp.substr(index + 1);
  143. offline_data_file_index = stoi(afterUnderscore) + 1;
  144. }
  145. else
  146. {
  147. offline_data_file_index = 1;
  148. }
  149. }
  150. else
  151. {
  152. offline_data_file_index = 0;
  153. }
  154. }
  155. delete_out_date_file(m_history_folder, HISDATA_SAVE_MAX_DAYS);
  156. delete_out_date_file(m_offline_folder_today, OFFLINE_DATA_SAVE_MAX_DAYS);
  157. }
  158. void DataStorageMgmt::to_new_day()
  159. {
  160. init_data_storage(m_folderPath,1);
  161. //如果正在保存数据,则关闭老文件,重新打开新文件
  162. if (m_offline_file_fs.is_open())
  163. {
  164. create_offline_data_file();
  165. }
  166. }
  167. //遍历文件,并删除存储期限外的文件
  168. void DataStorageMgmt::delete_out_date_file(const memepp::native_string dataFolderPath, uint16_t max_days)
  169. {
  170. try {
  171. auto now = std::chrono::system_clock::now();
  172. auto ninetyDaysAgo = now - std::chrono::hours(max_days); // 获取90天前的时间点
  173. for (const auto& dirEntry : ghcfs::directory_iterator(dataFolderPath))
  174. {
  175. if (dirEntry.is_directory())
  176. {
  177. std::string folderName = dirEntry.path().filename().string();
  178. if (folderName.length() != 8) // 校验文件夹名称长度
  179. continue;
  180. int year = std::stoi(folderName.substr(0, 4));
  181. int month = std::stoi(folderName.substr(4, 2));
  182. int day = std::stoi(folderName.substr(6, 2));
  183. std::tm tm = { 0 };
  184. tm.tm_year = year - 1900;
  185. tm.tm_mon = month - 1;
  186. tm.tm_mday = day;
  187. auto folderTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
  188. if (folderTime < ninetyDaysAgo)
  189. {
  190. ghcfs::remove_all(dirEntry); // 删除文件夹及其内容
  191. std::cout << "Deleted folder: " << dirEntry.path() << std::endl;
  192. }
  193. }
  194. }
  195. }
  196. catch (const std::exception& e)
  197. {
  198. string errmgs = "Error occurred while deleting files : " + string(e.what());
  199. std::cerr << errmgs << std::endl;
  200. }
  201. }
  202. // 存储全量数据到文件系统
  203. void DataStorageMgmt::save_data_to_file(const uint8_t data[], const size_t dataSize, const uint64_t timestamp)
  204. {
  205. if (isCanSave == false)
  206. return;
  207. auto strDateTime = mm_to<memepp::native_string>(get_datetime_string());
  208. if (strDateTime == m_strDateTime)
  209. {
  210. //同一个小时内,如果新创建文件需要增加1
  211. ++offline_data_file_index;
  212. }
  213. else
  214. {
  215. m_strDateTime = strDateTime;
  216. offline_data_file_index = 0;
  217. }
  218. #if MG_OS__WIN_AVAIL
  219. auto strfile_name = std::to_wstring(timestamp) + L".txt";
  220. auto m_history_file_path = m_history_folder_today + L"/" + strfile_name;
  221. #else
  222. auto strfile_name = std::to_string(timestamp) + ".txt";
  223. auto m_history_file_path = m_history_folder_today + "/" + strfile_name;
  224. #endif
  225. std::fstream hisdata_fs;
  226. hisdata_fs.open(m_history_file_path, std::ios::binary | std::ios::app);
  227. if (hisdata_fs.is_open())
  228. {
  229. // 写入 uint8_t 数据
  230. hisdata_fs.write(reinterpret_cast<const char*>(data), dataSize * sizeof(uint8_t));
  231. hisdata_fs.close();
  232. std::cout << "save history succful" << std::endl;
  233. }
  234. else
  235. {
  236. std::cout << "open histroy file faile" << std::endl;
  237. }
  238. }
  239. //通过时间戳读取历史数据
  240. void DataStorageMgmt::get_history_file_list(uint64_t &startTime, uint64_t &endTime, std::vector<ghcfs::path>& hisDataPath)
  241. {
  242. uint64_t startTimeTmp = 0;
  243. uint64_t endTimeTmp = 0;
  244. const auto folderPath = ghcfs::absolute(m_history_folder);
  245. if (!is_directory(folderPath)) {
  246. std::cout << "Invalid folder path." << std::endl;
  247. }
  248. for (const auto& dateFolder : ghcfs::directory_iterator(folderPath))
  249. {
  250. for (const auto& entry : ghcfs::directory_iterator(dateFolder))
  251. {
  252. if (ghcfs::is_directory(entry)) {
  253. continue;
  254. }
  255. const auto filePath = entry.path();
  256. const auto fileName = filePath.filename().string();
  257. const auto fileTime = std::stoll(fileName.substr(0, fileName.find('.')));
  258. if (fileTime < startTime) {
  259. continue;
  260. }
  261. if (fileTime > endTime) {
  262. break;
  263. }
  264. //获取其实时间戳和截止时间戳
  265. if (startTimeTmp == 0 || fileTime < startTimeTmp) {
  266. startTimeTmp = fileTime;
  267. }
  268. if (endTimeTmp == 0 || fileTime > endTimeTmp) {
  269. endTimeTmp = fileTime;
  270. }
  271. hisDataPath.push_back(filePath);
  272. }
  273. }
  274. startTime = startTimeTmp;
  275. endTime = endTimeTmp;
  276. }
  277. void DataStorageMgmt::read_history_data(const ghcfs::path filePath, std::vector<uint8_t>& historyData)
  278. {
  279. std::ifstream fileStream(filePath, std::ios::binary);
  280. if (fileStream.is_open())
  281. {
  282. const auto fileSize = ghc::filesystem::file_size(filePath);
  283. std::vector<uint8_t> fileContent(fileSize);
  284. fileStream.read((char*)fileContent.data(), fileSize);
  285. historyData.insert(historyData.end(), fileContent.begin(), fileContent.end());
  286. }
  287. }
  288. //当网关离线的时候,创建离线文件
  289. void DataStorageMgmt::create_offline_data_file()
  290. {
  291. if (isCanSave == false)
  292. return;
  293. auto strDateTime = mm_to<memepp::native_string>(get_datetime_string());
  294. #if MG_OS__WIN_AVAIL
  295. auto offline_file_path = m_offline_folder_today + L"/" + strDateTime + L".txt";
  296. #else
  297. auto offline_file_path = m_offline_folder_today + "/" + strDateTime + ".txt";
  298. #endif
  299. if (strDateTime == m_strDateTime)
  300. {
  301. //保证每次只打开一个文件
  302. if (!m_offline_file_fs.is_open())
  303. {
  304. m_offline_file_fs.open(offline_file_path, std::ios::binary | std::ios::app);
  305. std::cout << "open offline file:" <<std::endl;
  306. }
  307. }
  308. else
  309. {
  310. m_strDateTime = strDateTime;
  311. m_offline_file_fs.close();
  312. m_offline_file_fs.open(offline_file_path, std::ios::binary | std::ios::app);
  313. std::cout << "open new offline file:" << std::endl;
  314. }
  315. }
  316. //保存离线数据
  317. void DataStorageMgmt::save_offline_data_to_file(const uint8_t data[], const size_t dataSize)
  318. {
  319. if (isCanSave == false)
  320. return;
  321. if (m_offline_file_fs.is_open())
  322. {
  323. // 写入数据长度
  324. m_offline_file_fs.write(reinterpret_cast<const char*>(&dataSize), sizeof(std::size_t));
  325. // 写入 uint8_t 数据
  326. m_offline_file_fs.write(reinterpret_cast<const char*>(data), dataSize * sizeof(uint8_t));
  327. m_offline_file_fs.flush();
  328. std::cout << "save offline data" << std::endl;
  329. }
  330. else
  331. {
  332. std::cout << "can't open offline file" << std::endl;
  333. }
  334. check_to_next_hour();
  335. }
  336. //获取所有离线数据文件路径,等待发送
  337. void DataStorageMgmt::get_offline_flie_list(std::vector<ghc::filesystem::path>& offlineDataPath)
  338. {
  339. const auto folderPath = ghcfs::absolute(m_offline_folder);
  340. if (!is_directory(folderPath)) {
  341. std::cout << "Invalid offline folder path." << std::endl;
  342. }
  343. for (const auto& dateFolder : ghcfs::directory_iterator(folderPath))
  344. {
  345. for (const auto& entry : ghcfs::directory_iterator(dateFolder))
  346. {
  347. if (ghcfs::is_directory(entry)) {
  348. continue;
  349. }
  350. offlineDataPath.push_back(entry.path());
  351. }
  352. }
  353. }
  354. //读取离线数据
  355. void DataStorageMgmt::read_offline_data(const ghcfs::path offline_file_path, std::vector<std::vector<uint8_t>>& cache)
  356. {
  357. std::ifstream file;
  358. file.open(offline_file_path, std::ios::binary);
  359. if (file.is_open())
  360. {
  361. // 读取所有数据
  362. while (file.peek() != EOF)
  363. {
  364. // 读取数据长度
  365. std::size_t dataSize;
  366. file.read(reinterpret_cast<char*>(&dataSize), sizeof(std::size_t));
  367. if (dataSize > 160000)
  368. {
  369. continue;
  370. }
  371. // 读取数据
  372. std::vector<uint8_t> data(dataSize);
  373. file.read(reinterpret_cast<char*>(data.data()), dataSize * sizeof(uint8_t));
  374. // 添加到结果数组
  375. cache.push_back(data);
  376. }
  377. file.close();
  378. remove_file(offline_file_path);
  379. std::cout << "read offline data success:" << offline_file_path.string() << std::endl;
  380. }
  381. else
  382. {
  383. std::cout << "can't open offline file" << std::endl;
  384. }
  385. }
  386. void DataStorageMgmt::check_to_next_hour()
  387. {
  388. auto strDateTime = mm_to<memepp::native_string>(get_datetime_string());
  389. if (strDateTime != m_strDateTime)
  390. {
  391. std::cout << "check_to_next_hour and create offline file" << std::endl;
  392. create_offline_data_file();
  393. }
  394. }
  395. void DataStorageMgmt::remove_file(memepp::native_string filePath)
  396. {
  397. if (ghcfs::exists(filePath))
  398. {
  399. ghcfs::remove(filePath);
  400. std::cout << "delect file success" << std::endl;
  401. // 检查文件所在文件夹是否为空
  402. std::string folderPath = ghcfs::path(filePath).parent_path().string();
  403. if (ghcfs::is_empty(folderPath))
  404. {
  405. std::string folderPathTmp = folderPath.substr(folderPath.length() - 8, 8);
  406. auto nameTmp = memepp::string(folderPathTmp.c_str(), folderPathTmp.length());
  407. auto strTmp = get_date_string();
  408. //当天的文件名,不用删除
  409. if (nameTmp != strTmp)
  410. {
  411. // 删除文件夹
  412. ghcfs::remove(folderPath);
  413. std::cout << "delete folder sucess" << folderPath << std::endl;
  414. }
  415. }
  416. }
  417. }
  418. //停止存储离线数据
  419. void DataStorageMgmt::stop_save_offline()
  420. {
  421. if (m_offline_file_fs.is_open())
  422. {
  423. m_offline_file_fs.close();
  424. }
  425. }