FileAnalysisService.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. package com.jiayue.ipfcst.console.service;
  2. import com.jiayue.ipfcst.common.core.util.DateTimeUtil;
  3. import com.jiayue.ipfcst.common.core.util.NumberUtils;
  4. import com.jiayue.ipfcst.common.data.constant.enums.HolidayTypeEnum;
  5. import com.jiayue.ipfcst.common.data.constant.enums.PredictionModelEnum;
  6. import com.jiayue.ipfcst.common.data.entity.*;
  7. import com.jiayue.ipfcst.common.data.repository.ElectricFieldRepository;
  8. import com.jiayue.ipfcst.common.data.repository.HolidayCalendarRepository;
  9. import com.jiayue.ipfcst.common.data.service.BaseService;
  10. import com.jiayue.ipfcst.fileupload.util.FileUtil;
  11. import lombok.AllArgsConstructor;
  12. import lombok.SneakyThrows;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.apache.commons.io.FileUtils;
  15. import org.apache.commons.lang.StringUtils;
  16. import org.apache.commons.lang.time.DateFormatUtils;
  17. import org.springframework.stereotype.Service;
  18. import java.io.*;
  19. import java.math.BigDecimal;
  20. import java.math.RoundingMode;
  21. import java.nio.charset.StandardCharsets;
  22. import java.nio.file.Files;
  23. import java.nio.file.Paths;
  24. import java.text.ParseException;
  25. import java.text.SimpleDateFormat;
  26. import java.util.ArrayList;
  27. import java.util.Collection;
  28. import java.util.Date;
  29. import java.util.List;
  30. /**
  31. * 解析电科院NWP和DQ文件
  32. *
  33. * @author cuil
  34. * @version 2.0
  35. * @since 2018/12/03 11:24
  36. */
  37. @AllArgsConstructor
  38. @Service
  39. @Slf4j
  40. public class FileAnalysisService extends BaseService {
  41. ElectricFieldService electricFieldService;
  42. ForecastPowerShortTermService forecastPowerShortTermService;
  43. HolidayCalendarRepository holidayCalendarRepository;
  44. NwpService nwpService;
  45. FileAnalysisRecordService fileAnalysisRecordService;
  46. OverHaulPlanService overHaulPlanService;
  47. SysParameterService sysParameterService;
  48. ElectricFieldRepository electricFieldRepository;
  49. private final String deleteFilelog = "文件删除异常";
  50. private final String format = "yyyy-MM-dd HH:mm:ss";
  51. private final String systemErrorLog = "系统错误: ";
  52. private final String errorLog = "error";
  53. private final String analysisFaild = "文件解析失败";
  54. public static void mvFile(File file, String fdPath) {
  55. try {
  56. FileUtils.copyFile(file, new File(fdPath), true);
  57. } catch (IOException e) {
  58. log.error("文件移动错误", e);
  59. }
  60. }
  61. /**
  62. * 创建备份文件夹
  63. */
  64. public static String mkDirForTime(String targetRoot, String format) {
  65. String path;
  66. File file;
  67. if (StringUtils.isNotEmpty(format)) {
  68. long current = System.currentTimeMillis();
  69. path = DateFormatUtils.format(current, format);
  70. file = new File(targetRoot + File.separator + path + File.separator);
  71. } else {
  72. file = new File(targetRoot + File.separator);
  73. }
  74. if (!file.exists() && !file.isFile()) {
  75. if (file.mkdir()) {
  76. log.info("已创建文件夹");
  77. } else {
  78. log.info("创建文件夹失败,路径:" + file.getPath());
  79. }
  80. }
  81. return file.getPath() + File.separator;
  82. }
  83. @SneakyThrows
  84. public void analysisJob() {
  85. log.info("-----------------开始执行文件解析任务----------------------");
  86. long timeD = 15 * 60 * 1000L;
  87. Long currentDate = DateTimeUtil.getMillisecondsSubDay();//今日凌晨
  88. boolean flag;
  89. List<ElectricField> electricFieldList = electricFieldService.getAll();
  90. List<String> eList = new ArrayList<>();
  91. for (ElectricField electricField : electricFieldList) {
  92. eList.add(electricField.getStationCode());
  93. }
  94. String path = FileUtil.getDownloadFilePath();
  95. //downloadFile
  96. File dirFile = new File(path);
  97. //判断该目录是否存在,不存在时创建
  98. if (!dirFile.exists()) {
  99. dirFile.mkdirs();
  100. }
  101. log.info("系统扫描路径【" + dirFile.getPath() + "】");
  102. for (String stationCode : eList) {
  103. // downLoadFile/场站编号/new
  104. String dirFiles = dirFile.getPath() + File.separator + stationCode + File.separator + "new";
  105. File filePath = new File(dirFiles);
  106. if (!filePath.exists()) {
  107. filePath.mkdirs();
  108. }
  109. Collection<File> files = FileUtils.listFiles(filePath, new String[]{"RB"}, false);
  110. String dayStr = new SimpleDateFormat("yyyyMMdd").format(new Date());//当前时间格式化为年月日
  111. if (files.isEmpty()) {
  112. for (File file : files) {
  113. flag = false;
  114. String fileName = file.getName();
  115. if (!fileName.contains(dayStr)) {
  116. try {
  117. Files.delete(Paths.get(file.getPath()));
  118. log.info(fileName + "不是当天的文件,删除!");
  119. break;
  120. }catch (IOException e2){
  121. log.info(deleteFilelog,e2);
  122. }
  123. }
  124. if (fileName.length() < 30) {
  125. if (file.getName().startsWith("DQ")) {
  126. try {
  127. List<ForecastPowerShortTerm> listDq = fileAnalysisShortTerm(file, currentDate, stationCode);
  128. ForecastPowerShortTerm forecastPowerShortTerm;
  129. if (listDq.size() > 0) {
  130. //如果数据不全,进行补入
  131. while (listDq.get(listDq.size() - 1).getForecastTime() < DateTimeUtil.getMillisecondsSubDay() + 4 * 24 * 60 * 60 * 1000 - timeD) {
  132. forecastPowerShortTerm = new ForecastPowerShortTerm();
  133. forecastPowerShortTerm.setFpValue(listDq.get(listDq.size() - 96).getFpValue());//修正前值
  134. forecastPowerShortTerm.setGenDate(new Date()); //装机容量
  135. forecastPowerShortTerm.setForecastTime(currentDate);
  136. forecastPowerShortTerm.setPredictionModelEnum(PredictionModelEnum.E1);
  137. forecastPowerShortTerm.setStationCode(stationCode);
  138. listDq.add(forecastPowerShortTerm);
  139. }
  140. try {
  141. //短期数据修正
  142. Long startTime = listDq.get(0).getForecastTime();
  143. Long endTime = listDq.get(listDq.size() - 1).getForecastTime();//删除相同时间数据
  144. forecastPowerShortTermService.deleteBetweenAndGenTime(startTime, endTime, listDq, stationCode);
  145. flag = true;
  146. } catch (Exception e) {
  147. log.error("保存短期数据报错", e);
  148. flag = false;
  149. }
  150. } else {
  151. log.info(file.getName() + "文件数据内容为空、不能正常解析 、移除该文件、执行数据修正功能");
  152. flag = false;
  153. }
  154. } catch (Exception e) {
  155. flag = false;
  156. log.error("解析DQ文件失败", e);
  157. }
  158. }
  159. if (file.getName().startsWith("NWP")) {
  160. try {
  161. List<Nwp> listNwp = fileAnalysisNwp(file, stationCode);
  162. Nwp nwpData;
  163. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  164. if (listNwp.size() > 0) {
  165. while (listNwp.get(listNwp.size() - 1).getPreTime() < DateTimeUtil.getMillisecondsSubDay() + 4 * 24 * 60 * 60 * 1000 - timeD) {
  166. nwpData = new Nwp();
  167. long time = 0;
  168. try {
  169. time = sdf.parse(listNwp.get(listNwp.size() - 96).getPreDate()).getTime() + 24 * 60 * 60 * 1000;
  170. } catch (ParseException e) {
  171. e.printStackTrace();
  172. }
  173. nwpData.setFarmId(listNwp.get(listNwp.size() - 96).getFarmId());
  174. nwpData.setScDate(listNwp.get(listNwp.size() - 96).getScDate());
  175. nwpData.setScTime(listNwp.get(listNwp.size() - 96).getScTime());
  176. nwpData.setPreDate(sdf.format(time));
  177. nwpData.setPreTime(listNwp.get(listNwp.size() - 1).getPreTime() + timeD);
  178. nwpData.setT(listNwp.get(listNwp.size() - 96).getT());//温度
  179. nwpData.setRh(listNwp.get(listNwp.size() - 96).getRh());//湿度
  180. nwpData.setPressure(listNwp.get(listNwp.size() - 96).getPressure());//气压
  181. nwpData.setSwr(listNwp.get(listNwp.size() - 96).getSwr());//辐射
  182. nwpData.setLwr(listNwp.get(listNwp.size() - 96).getLwr());//辐射
  183. nwpData.setDiffuseRadiation(listNwp.get(listNwp.size() - 96).getDiffuseRadiation());//散接辐射
  184. nwpData.setDirectRadiation(listNwp.get(listNwp.size() - 96).getDirectRadiation());//直接辐射
  185. nwpData.setSenf(listNwp.get(listNwp.size() - 96).getSenf());//热感通量
  186. nwpData.setWs10(listNwp.get(listNwp.size() - 96).getWs10());//10 m 风速
  187. nwpData.setWs30(listNwp.get(listNwp.size() - 96).getWs30());//30 m 风速
  188. nwpData.setWs50(listNwp.get(listNwp.size() - 96).getWs50());//50 m 风速
  189. nwpData.setWs70(listNwp.get(listNwp.size() - 96).getWs70());//70 m 风速
  190. nwpData.setWs80(listNwp.get(listNwp.size() - 96).getWs80());//80 m 风速
  191. nwpData.setWs90(listNwp.get(listNwp.size() - 96).getWs90());//90 m 风速
  192. nwpData.setWs100(listNwp.get(listNwp.size() - 96).getWs100());//100 m 风速
  193. nwpData.setWs170(listNwp.get(listNwp.size() - 96).getWs170());//170 m 风速
  194. nwpData.setWd10(listNwp.get(listNwp.size() - 96).getWd10());//10 m 风向
  195. nwpData.setWd30(listNwp.get(listNwp.size() - 96).getWd30());//30 m 风向
  196. nwpData.setWd50(listNwp.get(listNwp.size() - 96).getWd50());//50 m 风向
  197. nwpData.setWd70(listNwp.get(listNwp.size() - 96).getWd70());//70 m 风向
  198. nwpData.setWd80(listNwp.get(listNwp.size() - 96).getWd80());//80 m 风向
  199. nwpData.setWd90(listNwp.get(listNwp.size() - 96).getWd90());//90 m 风向
  200. nwpData.setWd100(listNwp.get(listNwp.size() - 96).getWd100());//100 m 风向
  201. nwpData.setWd170(listNwp.get(listNwp.size() - 96).getWd170());//170 m 风向
  202. nwpData.setStationCode(stationCode);
  203. listNwp.add(nwpData);
  204. }
  205. } else {
  206. log.info(file.getName() + "文件数据内容为空、不能正常解析 、移除该文件、执行数据修正功能");
  207. }
  208. //保存NWP实时数据
  209. Long startTime = listNwp.get(0).getPreTime();
  210. Long endTime = listNwp.get(listNwp.size() - 1).getPreTime();//删除相同时间数据
  211. nwpService.deleteBetweenAndPreTime(startTime, endTime, listNwp, stationCode);
  212. flag = true;
  213. } catch (Exception e) {
  214. log.error("解析NWP文件失败", e);
  215. flag = false;
  216. }
  217. }
  218. if (flag) {
  219. //文件解析成功之后,保存记录
  220. saveFileParsingRecord(file, "1", stationCode);
  221. //移除文件备份到临时文件下
  222. moveFile(file);
  223. } else {
  224. //文件解析失败之后,保存记录
  225. saveFileParsingRecord(file, "0", stationCode);
  226. //移除文件备份到error文件下
  227. moveFileError(file);
  228. }
  229. }
  230. }
  231. }
  232. log.info("-----------------执行文件解析任务完成----------------------");
  233. }
  234. }
  235. /**
  236. * NWP解析
  237. *
  238. * @param file 文件路径
  239. * @return 样例集合
  240. */
  241. private List<Nwp> fileAnalysisNwp(File file, String stationCode) {
  242. List<Nwp> listNwp = new ArrayList<>();
  243. if (file.renameTo(file)) {
  244. try(
  245. InputStreamReader readNwp = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8.name());//考虑到编码格式
  246. BufferedReader bufferedReaderNwp = new BufferedReader(readNwp);){
  247. String lineTxt;
  248. Nwp nwpData;
  249. BigDecimal nwpDirectRadiation = new BigDecimal("0.7"); //直接辐射
  250. BigDecimal nwpDiffuseRadiation = new BigDecimal("0.3"); //散接辐射
  251. while ((lineTxt = bufferedReaderNwp.readLine()) != null) {
  252. //NWP文件按照Tab方式截取
  253. String[] datas = lineTxt.split("\t");
  254. if (datas.length == 35 && datas[0].startsWith("#")) {
  255. SimpleDateFormat sdf = new SimpleDateFormat(format);
  256. nwpData = new Nwp();
  257. //将截取的文件放入nwpData中
  258. nwpData.setFarmId(datas[1]);
  259. nwpData.setScDate(datas[2]);
  260. nwpData.setScTime(datas[3]);
  261. nwpData.setPreDate(datas[4]);
  262. nwpData.setPreTime(sdf.parse(datas[5]).getTime());//采集时间 与 短期预测时间关联
  263. nwpData.setT(NumberUtils.subtract(new BigDecimal(datas[6]), new BigDecimal("273.15")));//温度
  264. nwpData.setSenf(new BigDecimal(datas[11]).setScale(2, RoundingMode.HALF_UP));//感热
  265. nwpData.setSwr(new BigDecimal(datas[9]).setScale(2, RoundingMode.HALF_UP));//短波辐射(相当于总辐射)
  266. nwpData.setLwr(new BigDecimal(datas[10]).setScale(2, RoundingMode.HALF_UP));//短波辐射(相当于总辐射)
  267. nwpData.setPressure(new BigDecimal(datas[8]).setScale(2, RoundingMode.HALF_UP));//地表气压
  268. nwpData.setRh(new BigDecimal(datas[7]).setScale(2, RoundingMode.HALF_UP));//2m相对湿度
  269. nwpData.setDiffuseRadiation(new BigDecimal(datas[9]).multiply(nwpDiffuseRadiation).setScale(2, RoundingMode.HALF_UP));//散接辐射
  270. nwpData.setDirectRadiation(new BigDecimal(datas[9]).multiply(nwpDirectRadiation).setScale(2, RoundingMode.HALF_UP));//直接辐射
  271. nwpData.setWs10(new BigDecimal(datas[19]).setScale(2, RoundingMode.HALF_UP));
  272. nwpData.setWs30(new BigDecimal(datas[20]).setScale(2, RoundingMode.HALF_UP));
  273. nwpData.setWs50(new BigDecimal(datas[21]).setScale(2, RoundingMode.HALF_UP));
  274. nwpData.setWs70(new BigDecimal(datas[22]).setScale(2, RoundingMode.HALF_UP));
  275. nwpData.setWs80(new BigDecimal(datas[23]).setScale(2, RoundingMode.HALF_UP));
  276. nwpData.setWs90(new BigDecimal(datas[24]).setScale(2, RoundingMode.HALF_UP));
  277. nwpData.setWs100(new BigDecimal(datas[25]).setScale(2, RoundingMode.HALF_UP));
  278. nwpData.setWs170(new BigDecimal(datas[26]).setScale(2, RoundingMode.HALF_UP));
  279. nwpData.setWd10(new BigDecimal(datas[27]).setScale(2, RoundingMode.HALF_UP));
  280. nwpData.setWd30(new BigDecimal(datas[28]).setScale(2, RoundingMode.HALF_UP));
  281. nwpData.setWd50(new BigDecimal(datas[29]).setScale(2, RoundingMode.HALF_UP));
  282. nwpData.setWd70(new BigDecimal(datas[30]).setScale(2, RoundingMode.HALF_UP));
  283. nwpData.setWd80(new BigDecimal(datas[31]).setScale(2, RoundingMode.HALF_UP));
  284. nwpData.setWd90(new BigDecimal(datas[32]).setScale(2, RoundingMode.HALF_UP));
  285. nwpData.setWd100(new BigDecimal(datas[33]).setScale(2, RoundingMode.HALF_UP));
  286. nwpData.setWd170(new BigDecimal(datas[34]).setScale(2, RoundingMode.HALF_UP));
  287. nwpData.setStationCode(stationCode);
  288. listNwp.add(nwpData);
  289. }
  290. }
  291. } catch (IOException | ParseException | RuntimeException e) {
  292. log.error(systemErrorLog, e);
  293. // 进行告警
  294. File destFile = new File(file.getPath().replaceFirst("new", systemErrorLog));
  295. if (destFile.exists()) {
  296. try {
  297. Files.delete(Paths.get(destFile.getPath()));
  298. }catch (IOException e2){
  299. log.info(deleteFilelog,e2);
  300. }
  301. }
  302. try {
  303. FileUtils.moveFile(file, destFile);
  304. } catch (IOException e1) {
  305. log.error(file.getName() + analysisFaild, e);
  306. }
  307. }
  308. }
  309. return listNwp;
  310. }
  311. /**
  312. * 短期解析
  313. *
  314. * @param file 文件路径
  315. * @param currentDate 当前时间
  316. * @return 样例集合
  317. */
  318. private List<ForecastPowerShortTerm> fileAnalysisShortTerm(File file, Long currentDate, String stationCode) {
  319. SimpleDateFormat sdf = new SimpleDateFormat(format);
  320. List<ForecastPowerShortTerm> forecastPowerShortTerm = new ArrayList<>();
  321. // 当文件未被使用时,进行解析上报
  322. if (file.renameTo(file)) {
  323. String stringLine;
  324. ForecastPowerShortTerm stf;
  325. try (
  326. InputStreamReader read = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
  327. BufferedReader bufferedReader = new BufferedReader(read);){
  328. while ((stringLine = bufferedReader.readLine()) != null) {
  329. String[] string_arr = stringLine.split("\t");
  330. if (string_arr.length == 4 && string_arr[0].startsWith("#") && StringUtils.isNotEmpty(string_arr[2])) {
  331. stf = new ForecastPowerShortTerm();
  332. stf.setFpValue(new BigDecimal(string_arr[3] + ""));
  333. stf.setForecastTime(sdf.parse(string_arr[2]).getTime());
  334. stf.setGenDate(new Date(currentDate));
  335. stf.setPredictionModelEnum(PredictionModelEnum.E1);
  336. stf.setStationCode(stationCode);
  337. forecastPowerShortTerm.add(stf);
  338. }
  339. }
  340. } catch (Exception e) {
  341. log.error(systemErrorLog, e);
  342. // 进行告警
  343. File destFile = new File(file.getPath().replaceFirst("new", systemErrorLog));
  344. if (destFile.exists()) {
  345. try {
  346. Files.delete(Paths.get(destFile.getPath()));
  347. }catch (IOException e2){
  348. log.info(deleteFilelog,e2);
  349. }
  350. }
  351. try {
  352. FileUtils.moveFile(file, destFile);
  353. } catch (IOException e1) {
  354. log.error(file.getName() +analysisFaild, e);
  355. }
  356. }
  357. }
  358. return forecastPowerShortTerm;
  359. }
  360. /**
  361. * 移动文件到临时目录下
  362. *
  363. * @param file 文件
  364. */
  365. private void moveFile(File file) {
  366. // 移动文件到处理目录
  367. File destFile = new File(file.getPath().replaceFirst("new", "backupsTemp"));
  368. log.info("move file :{}, dest file:{}", file, destFile);
  369. if (destFile.exists()) {
  370. try {
  371. Files.delete(Paths.get(destFile.getPath()));
  372. }catch (IOException e2){
  373. log.info(deleteFilelog,e2);
  374. }
  375. }
  376. try {
  377. FileUtils.moveFile(file, destFile);
  378. } catch (IOException e) {
  379. log.error("系统移除文件错误:", e);
  380. // 进行告警
  381. }
  382. moveFileBackups(destFile.getParent());
  383. }
  384. /**
  385. * 移动文件到处理目录
  386. *
  387. * @param filePath 文件路径
  388. */
  389. private void moveFileBackups(String filePath) {
  390. String targetRoot = filePath.replaceFirst("backupsTemp", "backups");
  391. String path = mkDirForTime(targetRoot, null);
  392. path = mkDirForTime(path, "yyyyMMdd");
  393. // 移动文件夹内容
  394. File sourceFile = new File(filePath);
  395. if (sourceFile.exists()) {
  396. try {
  397. File[] files = sourceFile.listFiles();
  398. if (files != null && files.length > 0) {
  399. for (File f : files) {
  400. if (f.renameTo(new File(path + f.getName()))) {
  401. log.info("move file :{}, dest file:{}", path, f.getName());
  402. }
  403. }
  404. }
  405. } catch (Exception e) {
  406. // 进行告警
  407. }
  408. }
  409. }
  410. /**
  411. * 移动文件到处理错误目录下
  412. *
  413. * @param file 文件
  414. */
  415. private void moveFileError(File file) {
  416. File destFile = new File(file.getPath().replaceFirst("new", systemErrorLog));
  417. if (destFile.exists()) {
  418. try {
  419. Files.delete(Paths.get(destFile.getPath()));
  420. }catch (IOException e2){
  421. log.info(deleteFilelog,e2);
  422. }
  423. }
  424. try {
  425. FileUtils.moveFile(file, destFile);
  426. } catch (IOException e) {
  427. log.error(file.getName() + analysisFaild, e);
  428. }
  429. }
  430. /**
  431. * 保存文件解析记录
  432. *
  433. * @param file 文件信息
  434. * @param fileStatus 文件解析状态 1:表示解析成功 0:解析失败
  435. */
  436. private void saveFileParsingRecord(File file, String fileStatus, String staticCode) {
  437. String fileType;
  438. if (file.getName().startsWith("JH")) {
  439. fileType = "JH";//假期文件
  440. } else if (file.getName().startsWith("DQ")) {
  441. fileType = "DQ";//短期文件
  442. } else {
  443. fileType = "NWP";//NWP文件
  444. }
  445. FileAnalysisRecord fileParsingRecord = new FileAnalysisRecord();
  446. fileParsingRecord.setFileTitle(file.getName());
  447. fileParsingRecord.setFileType(fileType);
  448. fileParsingRecord.setFileStatus(fileStatus);
  449. fileParsingRecord.setFilePath(file.getPath());
  450. fileParsingRecord.setFileDescription(DateTimeUtil.getStringDate() + " 正常解析文件");
  451. fileParsingRecord.setStationCode(staticCode);
  452. fileAnalysisRecordService.save(fileParsingRecord);
  453. }
  454. }