file.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. const fs = require('fs');
  2. const path = require('path');
  3. const {logger} = require("./logger");
  4. const {rustConfig} = require("../config");
  5. const http = require("./http");
  6. const readline = require('readline');
  7. // 检查目录是否存在,不存在新建
  8. function checkPathSync(filePath) {
  9. // 将相对路径转换为绝对路径
  10. const directoryPath = path.resolve(filePath);
  11. // 同步检查目录是否存在
  12. if (!fs.existsSync(directoryPath)) {
  13. // 目录不存在,需要创建它
  14. logger.info('目录不存在,正在创建...');
  15. try {
  16. // 同步创建目录
  17. fs.mkdirSync(directoryPath, {recursive: true});
  18. logger.info('目录已成功创建');
  19. } catch (error) {
  20. // 创建目录失败
  21. logger.error('创建目录失败:', error);
  22. return false
  23. }
  24. } else {
  25. // 目录已存在
  26. logger.info('目录已存在');
  27. }
  28. return true
  29. }
  30. // 检查文件是否存在
  31. function checkFilePath(filePath) {
  32. // 同步检查文件是否存在
  33. const directoryPath = path.resolve(filePath);
  34. if (fs.existsSync(directoryPath)) {
  35. logger.info('文件存在:' + filePath);
  36. return true
  37. } else {
  38. logger.error('文件不存在:' + filePath);
  39. return false
  40. }
  41. }
  42. // 创建文件
  43. function writeFile(filePath, text, breakFun) {
  44. fs.writeFile(filePath, text, (err) => {
  45. if (err) {
  46. logger.error('写入文件时发生错误:', err);
  47. breakFun(err)
  48. } else {
  49. logger.log('文件已成功写入!');
  50. breakFun(null, true)
  51. }
  52. });
  53. }
  54. // 同步复制
  55. function copyFileSync(source, destination) {
  56. try {
  57. // 同步复制文件
  58. fs.copyFileSync(source, destination);
  59. // logger.info("成功");
  60. return true;
  61. } catch (err) {
  62. return false;
  63. // logger.info("失败");
  64. }
  65. }
  66. // // 读取日志(倒叙)指定行数
  67. // function readLastNLines(filePath, n) {
  68. // const content = fs.readFileSync(filePath, 'utf8');
  69. // const lines = content.trim().split('\n');
  70. // const lastNLines = lines.slice(-n).join('\n');
  71. //
  72. // // 此处处理或输出最后n行的内容
  73. // // console.log(lastNLines);
  74. // return lastNLines.split("\n").reverse();
  75. // }
  76. // 下载文件
  77. function dowFile(url, fileName, dowPath, headers) {
  78. return http.dowFile(url, fileName, dowPath, headers)
  79. }
  80. // 删除文件
  81. function delFile() {
  82. }
  83. /***********************************/
  84. function getLastFile(dirPath, number, callback) {
  85. fs.readdir(dirPath, async (err, files) => {
  86. if (err) {
  87. logger.error(`无法列出目录。`, err);
  88. // process.exit(1);
  89. } else {
  90. let fileList = [];
  91. //提示日志默认是根据日志生成的,拿到的files 也是 按照生成日志排序的,所以
  92. // 按照倒叙获取,如果一个文件内容满足num,就不在继续查询,如果不够,继续获取文件
  93. // logger.info("文件:",files)
  94. for (file of files) {
  95. const filePath = path.join(dirPath, file);
  96. const stats = await fs.promises.stat(filePath);
  97. if (stats.isFile()) {
  98. fileList.push({name: file, time: stats.birthtime.getTime()});
  99. // logger.info("----------------文件:" + filePath + "时间:" + stats.birthtime.getTime())
  100. }
  101. }
  102. fileList.sort((a, b) => b.time - a.time);
  103. // for (a of fileList) {
  104. // logger.info("cccccccccc文件cccccccc22222222:" + a.name + "\ttime:" + a.time)
  105. // }
  106. lastFileList = fileList.slice(0, number != -1 ? number : fileList.length);
  107. lastFileNameList = lastFileList.map((item) => item.name);
  108. callback(lastFileNameList.reverse(), lastFileList.reverse());
  109. }
  110. });
  111. }
  112. // 读取日志(倒叙)指定行数
  113. async function readLastNLines(dirPath, filePathList, n) {
  114. try {
  115. const fileList = [];
  116. var count = 0;
  117. for (var i = filePathList.length - 1; i >= 0; i--) {
  118. var item = filePathList[i];
  119. const filepath = `${dirPath}/${item}`;
  120. logger.info("日志文件:" + filepath)
  121. //老版本 加载整个文件
  122. // const content = fs.readFileSync(`${filepath}`, "utf8");
  123. // let lines = content.trim().split("\n");
  124. //新版本:流式读取和逐行处理
  125. const lines = await readLinesFromEnd(filepath, n - count);
  126. // logger.info("日:" + lines)
  127. fileList.push({
  128. filePath: item,
  129. lines: lines,
  130. })
  131. count += lines.length;
  132. if (count >= n) {
  133. break
  134. }
  135. }
  136. fileList.reverse();
  137. const allFile = [].concat(...fileList.map((item) => item.lines));
  138. const lastNLines = allFile.slice(-n).reverse();
  139. return lastNLines;
  140. } catch (e) {
  141. logger.info('获取日志异常了~~1111111111111111', e);
  142. }
  143. }
  144. async function getRecentLogs(dirPath,logFiles, requiredLogs = 100) {
  145. let logs = [];
  146. for (const file of logFiles) {
  147. let log = [];
  148. // 创建文件流
  149. const filepath = `${dirPath}/${file}`;
  150. const fileStream = fs.createReadStream(filepath);
  151. const rl = readline.createInterface({
  152. input: fileStream,
  153. crlfDelay: Infinity
  154. });
  155. for await (const line of rl) {
  156. // logs.push(line);
  157. log.push(line);
  158. // 如果已读取到必要的日志条数,则停止
  159. if (logs.length >= requiredLogs) {
  160. return logs.slice(0, requiredLogs);
  161. }
  162. }
  163. logs.push(...log.reverse());
  164. }
  165. return logs; // 如果日志不够500条,返回现有日志
  166. }
  167. async function readLinesFromEnd(filePath, maxLines) {
  168. const lines = [];
  169. const fileSize = fs.statSync(filePath).size;
  170. const chunkSize = 1024 * 10 * 5; // 每次读取的块大小
  171. if (fileSize < chunkSize) {
  172. const fileStream = fs.createReadStream(filePath, {
  173. start: Math.max(0, 0),
  174. end: fileSize
  175. });
  176. let buffer = '';
  177. for await (const chunk of fileStream) {
  178. buffer = chunk + buffer;
  179. let lineEndIndex = buffer.length;
  180. while (lineEndIndex >= 0 && lines.length < maxLines) {
  181. const lineStartIndex = buffer.lastIndexOf('\n', lineEndIndex - 1);
  182. if (lineStartIndex === -1) {
  183. break;
  184. }
  185. const line = buffer.substring(lineStartIndex + 1, lineEndIndex).trim();
  186. if (line) {
  187. lines.push(line);
  188. }
  189. lineEndIndex = lineStartIndex;
  190. }
  191. if (lines.length >= maxLines) {
  192. break;
  193. }
  194. }
  195. } else {
  196. let forNum = (fileSize / chunkSize) + 1;
  197. for (let i = 1; i <= forNum; i++) {
  198. let position = fileSize - chunkSize * i;
  199. let z = position + chunkSize
  200. const fileStream = fs.createReadStream(filePath, {
  201. start: Math.max(position, 0),
  202. end: z
  203. });
  204. let buffer = '';
  205. for await (const chunk of fileStream) {
  206. buffer = chunk + buffer;
  207. let lineEndIndex = buffer.length;
  208. while (lineEndIndex >= 0 && lines.length < maxLines) {
  209. const lineStartIndex = buffer.lastIndexOf('\n', lineEndIndex - 1);
  210. if (lineStartIndex === -1) {
  211. break;
  212. }
  213. const line = buffer.substring(lineStartIndex + 1, lineEndIndex).trim();
  214. if (line) {
  215. lines.push(line);
  216. }
  217. lineEndIndex = lineStartIndex;
  218. }
  219. if (lines.length >= maxLines) {
  220. break;
  221. }
  222. position -= chunkSize;
  223. if (position < 0) {
  224. position = 0;
  225. }
  226. }
  227. }
  228. }
  229. return lines.reverse();
  230. }
  231. async function readLines(filePath, maxLines) {
  232. const fileStream = fs.createReadStream(filePath);
  233. const rl = readline.createInterface({
  234. input: fileStream,
  235. crlfDelay: Infinity
  236. });
  237. const lines = [];
  238. for await (const line of rl) {
  239. lines.push(line);
  240. if (lines.length >= maxLines) {
  241. break;
  242. }
  243. }
  244. rl.close();
  245. fileStream.close();
  246. return lines;
  247. }
  248. module.exports = {
  249. dowFile,
  250. checkFilePath,
  251. checkPathSync,
  252. writeFile,
  253. copyFileSync,
  254. readLastNLines,
  255. getRecentLogs,
  256. getLastFile
  257. }