From 046a86a232407d6bb5c1a2f37feff76714243ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Fri, 23 Jan 2026 17:17:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=B9=E6=AC=A1=E8=AF=BB=E5=8F=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=EF=BC=8C=E4=B8=8D=E5=86=8D=E4=B8=80=E6=AC=A1=E4=B8=80?= =?UTF-8?q?=E6=AC=A1=E8=AF=BB=E5=8F=96=20=E5=B0=86=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=AF=8F=E6=97=A9=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/common/target/common-1.0.0.jar | Bin 19366 -> 19368 bytes .../target/maven-archiver/pom.properties | 2 +- modules/filter/target/filter-1.0.0.jar | Bin 11388 -> 11388 bytes .../web/service/client/DeleteServer.java | 217 ++++++++++++++++++ .../service/cron/PLCConnectionExample.java | 61 ++++- 5 files changed, 269 insertions(+), 11 deletions(-) create mode 100644 web/src/main/java/com/zhehekeji/web/service/client/DeleteServer.java diff --git a/modules/common/target/common-1.0.0.jar b/modules/common/target/common-1.0.0.jar index 19779831b3da5964c5eebd3c88a7db9265a77d56..a49f390a7048480dbf3d8938e60d2316a5b598cc 100644 GIT binary patch delta 1373 zcmZ2BopHrLrKUW`B#l&wKf*`w)Rfb3r;*QCoj20{)MUy8oT0G&wqpkqW`+^OD+iOh+HL9%u)G08$`@RiwVlIGI$I%Q_*-6 zOs{z`l%;2r#0b_gd5WzjgmKW;9K!fxYsZorWFE8G&Q6Mj6Xckb^&vuH zg?#Wj6Kr4bwBuQ^gVa}>grP-XFbmPojvvB zsh5t{NgrR9EC?5s&SJKI7=};pM2X{7V14`DJEgY$p(y)d}s>oU8I=Y zKr-T!?O8Y{SG({)baVs7n;_!)oV=4yyKqCqZvn**Lc|R`*tFr^-~cB}`|_$Srx+O+ z4l*+^Xu-X~z_6t8Cq$1flj!6uSEwCTu2M|gEKs{;C!d0e-vWxiWdn=rbMj2qWfz+K z#to{++D(e-HwRQs8YHd&imiWP%@ad`mO28{r74QVdfae>^0-A12K@mVbd3)zXW+p) znV+9;@(g!~VSB=}e=i5djfVsSg9eIWCxqb|y4>8Cw7oZ9E49gF1@ht#WY1 z58Ndo!S~l)ipfYBDlQK;VBfa48HZRI7%F)f7}QVTG`0oK0JymbcV7Kjx@FDQY<@p~Nx;g)|BZA)*X) zZ(;OB4zUn5*h~m2EF>@_E7pg75hZ=A2=z}6?Y(=it=Yld`@7%!dw$Pz_dM_QPNJui zV78P=C?(*pWsYP=2cuK4Xw7uCoUQ9vUsFN1+`42lHQI(f<9nO9N>B6(m;3uU*OEc1 z=Jb^=sZnFpfS^TfGwl$(#0Q1e>iRlksG{T7N{UYg6A2>*6+|`$?ZgHQ#)-88@P?5L ziP2K(orvaSN)ag(MiJ$PcS{)Fb$dbQ(>|2AUJl=@v|c7+gu?O9RbQ1+yrN3J)s&4C zRdN7Q;Vcv9or>Qqit=?dOetUZV zG5YiSNU2VuD|Zh3bo-x@3_M^J&5u}FlBW2AP*Sl6ZxA;v6F6;HJe)2PwOkQP z`sD)OP?U-bxrjJpxTvLJUAQ`^pGSKy7__$>G7${CP)uw2p}M_o|J*h7uS;S9SQ%2_ zsEQZ6)PffK_ZG9{P&}en!I@&Qjs?V-bb@cKPS7Usz9DlM;+p~+O4bRvFQ3Y3K2HL$ zPX<6{h{lj17*=O!0)@V+YL03|)BjBYKyrv!WfH`Br5aqNqm(5_vv|&xt>WW_f~sa` zC*n{ilF;Eu3yIglC#CCgXoQU=PjIk{Q$e#$i8(vsyc~SQCF+AS#(&~JCLk&B5(yR- zra9;=OMw$MTFalB)}G|1XJ`O4(Th`On2}Hqjb#xDfkTCy>d?I=;K)zQCRkZ!l}Rl; F`3Hr6Qy2gM diff --git a/modules/common/target/maven-archiver/pom.properties b/modules/common/target/maven-archiver/pom.properties index 7ff955e..721b4ec 100644 --- a/modules/common/target/maven-archiver/pom.properties +++ b/modules/common/target/maven-archiver/pom.properties @@ -1,5 +1,5 @@ #Generated by Maven -#Sat May 24 09:59:24 CST 2025 +#Fri Jan 23 15:42:05 CST 2026 groupId=com.zhehekeji artifactId=common version=1.0.0 diff --git a/modules/filter/target/filter-1.0.0.jar b/modules/filter/target/filter-1.0.0.jar index 9acee5d7688ec96709ae97e282a176fc95cee0f1..d1356cef97efcb7378e28be39c10c4bbe3e640ce 100644 GIT binary patch delta 471 zcmewp@h5^Wz?+#xgn@yBgF&^?JZ2)_Ru(XQT$#nC7RY}m2c{9F>-RzYHkq5A2k;kLuzuIx)#L4J?e%Kvkt0TLKy$l-60H54L^v6*&2}$ z#t)4U2qQo<1H#y&846*DYDGX8g<3%n#&IpEE*0%Sh@UF89l(B?yjL5lOH3yX03gnf Al>h($ delta 471 zcmewp@h5^Wz?+#xgn@yBgCR9pHF_f7Ru(XQT$v@if+u?7J2@~tS%6W4MK)SBda@0p zK7^6aXa-?CWK^B3ug=cH%)$jUhk*gC>>;BGOBm3=$&yTpU=t_XF=;{=*-YjT#xf>5 zunC)AFkNF41ZkVLSZ+ZyBLl-9Al91vfKOtwwx;OjKb)zI5QVASSJt~nUnL?>>-RzYHkq5A2k;kLuzuIx)#L4J?e%Kvkt0TLKy$l-60H5 z4L^v6*&2}$#t)4U2qQo<1H#y&846*DYDGX8g<3%n#&IpEE*0%Sh@UF89l(B?yjMFE J;w3SiGyp#vi8%lO diff --git a/web/src/main/java/com/zhehekeji/web/service/client/DeleteServer.java b/web/src/main/java/com/zhehekeji/web/service/client/DeleteServer.java new file mode 100644 index 0000000..a4e74d8 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/client/DeleteServer.java @@ -0,0 +1,217 @@ +package com.zhehekeji.web.service.client; + + +import com.sourceforge.snap7.moka7.S7Client; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileStore; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + +@Slf4j +@Service +public class DeleteServer { + + + @PostConstruct + public void PlcConnectionPool() { + CompletableFuture.runAsync(() -> cleanStorage("E:\\data\\mp4\\record\\live")); + } + + /** + * 清理存储空间 + * @param rootPath 根文件夹路径,例如 "D:/storage" + */ + private void cleanStorage(String rootPath) { + try { + log.info("开始清理存储空间: {}", rootPath); + + Path root = Paths.get(rootPath); + if (!Files.exists(root) || !Files.isDirectory(root)) { + log.error("存储路径不存在或不是目录: {}", rootPath); + return; + } + + // 获取所有相机文件夹下的日期文件夹 + List allDateFolders = getAllDateFolders(root); + log.info("共找到 {} 个日期文件夹", allDateFolders.size()); + + // 按日期升序排序(最早的在前面) + allDateFolders.sort(Comparator.comparing(DateFolder::getDate)); + + // 第一轮清理:删除两个月前的文件夹 + LocalDate twoMonthsAgo = LocalDate.now().minusMonths(2); + int deletedOld = deleteFoldersBeforeDate(allDateFolders, twoMonthsAgo); + log.info("删除两个月前的文件夹: {} 个", deletedOld); + + // 检查磁盘空间 + if (getDiskUsagePercent(root) < 70.0) { + log.info("磁盘空间充足({}%),清理完成", getDiskUsagePercent(root)); + return; + } + + // 第二轮清理:继续删除最旧的文件夹,直到空间充足或删完 + int deletedMore = deleteOldestFolders(allDateFolders, twoMonthsAgo, root); + log.info("继续删除最旧的文件夹: {} 个", deletedMore); + + log.info("存储空间清理完成,当前使用率: {}%", getDiskUsagePercent(root)); + + } catch (Exception e) { + log.error("清理存储空间失败", e); + } + } + + /** + * 获取所有相机文件夹下的日期文件夹 + */ + private List getAllDateFolders(Path root) throws IOException { + List result = new ArrayList<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + // 遍历根目录下的相机文件夹 + Files.list(root) + .filter(Files::isDirectory) + .forEach(cameraDir -> { + try { + // 遍历相机文件夹下的日期文件夹 + Files.list(cameraDir) + .filter(Files::isDirectory) + .forEach(dateDir -> { + try { + // 尝试解析文件夹名为日期 + LocalDate date = LocalDate.parse(dateDir.getFileName().toString(), formatter); + result.add(new DateFolder(dateDir.toFile(), date, cameraDir.getFileName().toString())); + } catch (DateTimeParseException e) { + // 文件夹名不符合日期格式,跳过 + } + }); + } catch (IOException e) { + log.error("遍历相机文件夹失败: {}", cameraDir, e); + } + }); + + return result; + } + + /** + * 删除指定日期之前的文件夹 + */ + private int deleteFoldersBeforeDate(List dateFolders, LocalDate beforeDate) { + int count = 0; + Iterator iterator = dateFolders.iterator(); + + while (iterator.hasNext()) { + DateFolder folder = iterator.next(); + if (folder.getDate().isBefore(beforeDate)) { + if (deleteFolder(folder.getFile())) { + count++; + } + iterator.remove(); + } + } + + return count; + } + + /** + * 继续删除最旧的文件夹,直到空间充足 + */ + private int deleteOldestFolders(List dateFolders, LocalDate minDate, Path root) { + int count = 0; + Iterator iterator = dateFolders.iterator(); + + while (iterator.hasNext() && getDiskUsagePercent(root) >= 70.0) { + DateFolder folder = iterator.next(); + + if (deleteFolder(folder.getFile())) { + count++; + log.info("删除文件夹: {}/{} (日期: {}), 当前使用率: {}%", + folder.getCameraName(), folder.getFile().getName(), folder.getDate(), getDiskUsagePercent(root)); + } + + iterator.remove(); + } + + return count; + } + + /** + * 删除文件夹及其内容 + */ + private boolean deleteFolder(File folder) { + try { + if (folder.exists() && folder.isDirectory()) { + Files.walk(folder.toPath()) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + + log.info("已删除文件夹: {}", folder.getAbsolutePath()); + return true; + } + return false; + } catch (IOException e) { + log.error("删除文件夹失败: {}", folder.getAbsolutePath(), e); + return false; + } + } + + /** + * 获取磁盘使用率百分比 + */ + private double getDiskUsagePercent(Path path) { + try { + FileStore store = Files.getFileStore(path); + long total = store.getTotalSpace(); + long free = store.getUsableSpace(); + long used = total - free; + return (used * 100.0) / total; + } catch (IOException e) { + log.error("获取磁盘空间失败", e); + return 100.0; + } + } + + /** + * 日期文件夹辅助类 + */ + private static class DateFolder { + private final File file; + private final LocalDate date; + private final String cameraName; + + public DateFolder(File file, LocalDate date, String cameraName) { + this.file = file; + this.date = date; + this.cameraName = cameraName; + } + + public File getFile() { + return file; + } + + public LocalDate getDate() { + return date; + } + + public String getCameraName() { + return cameraName; + } + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java b/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java index a550390..c3ce8be 100644 --- a/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java +++ b/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java @@ -13,11 +13,17 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.io.BufferedReader; +import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.nio.file.FileStore; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.*; import java.util.concurrent.*; @Configuration @@ -57,6 +63,7 @@ public class PLCConnectionExample { client.ConnectTo(plcIp,plcRack,plcSlot); // IP, Rack, Slot connectionPool.offer(client); } + } @@ -247,12 +254,11 @@ public class PLCConnectionExample { // 读数据 @Scheduled(fixedDelay = POLL_INTERVAL) void server(){ + // 批量读取所有C1/C2/C3地址 + Map dataMap = readPlcDataTaskIds(); - for (String key : addressMap.keySet()){ - if (key.contains("out") || !key.contains("C")) { - continue; - } - int i = readPlcDataTaskId(addressMap.get(key)); + for (String key : dataMap.keySet()){ + int i = dataMap.get(key); if (i == 0) continue; if (taskMap.get(key) == null || taskMap.get(key) != i) { log.info("任务号变化" + key + ":" + i); @@ -262,9 +268,7 @@ public class PLCConnectionExample { executorService.submit(() -> processKey(i, plcId, key)); if(key.contains("C1")){ - writePlcDataTaskId(key+"-out", i); - } } } @@ -335,6 +339,43 @@ public class PLCConnectionExample { } return false; } + /** + * 批量读取所有C1/C2/C3地址的任务号 + * @return Map,例如:{"001-C1": 100, "001-C2": 200, ...} + */ + public Map readPlcDataTaskIds(){ + S7Client client = getConnection(); + try { + // 批量读取0-44字节区域 + byte[] buffer = new byte[48]; + int result = client.ReadArea(S7.S7AreaDB, dbNumber, 0, 48, buffer); + + if (result != 0) { + updateConnection(client); + log.info("批量读取失败,错误码: " + result); + return new HashMap<>(); + } + + // 解析所有C1/C2/C3地址的值 + Map resultMap = new HashMap<>(); + for (String key : addressMap.keySet()) { + if (key.contains("out") || !key.contains("C")) { + continue; + } + int offset = addressMap.get(key); + int value = S7.GetDIntAt(buffer, offset); + resultMap.put(key, value); + } + + return resultMap; + } catch (Exception e) { + log.error("批量读取异常", e); + return new HashMap<>(); + } finally { + returnConnection(client); + } + } + public boolean writePlcDataStatusErr(String plcId,int digit){ if (digit==1){