本帖最后由 xiaojin 于 2025-6-9 09:15 编辑
在小安派bw21中实现sd卡的滚动存储- // 生成文件夹名时间戳 (格式: YYYY-MM-DD)
- String generateDirName(time_t time)
- {
- char fileName[11]; // YYYY-MM-DD + null
- snprintf(fileName, sizeof(fileName), "%04d-%02d-%02d",
- year(),month(),day());
- return String(fileName);
- }
- // 生成文件名时间戳 (格式: hhmmss)
- String generatefileName(time_t time)
- {
- char fileName[7]; // hhmmss + null
- snprintf(fileName, sizeof(fileName), "%02d%02d%02d",
- hour(),minute(),second());
- return String(fileName);
- }
- // 从文件夹名解析时间戳 (格式: YYYY-MM-DD)
- uint32_t parseFolderTimestamp(const char *folderName)
- {
- // 快速验证长度和基本格式
- if (strlen(folderName) < 10 || folderName[4] != '-' || folderName[7] != '-') {
- return 0;
- }
- // 直接验证所有数字位,避免内存拷贝
- for (uint8_t pos : {0, 1, 2, 3, 5, 6, 8, 9}) {
- if (!isdigit(folderName[pos])) {
- #ifdef DEBUG
- Serial.print("Invalid char in: ");
- Serial.println(folderName);
- #endif
- return 0;
- }
- }
- // 直接计算时间戳值(避免字符串操作)
- return (folderName[0] - '0') * 10000000 + // 年 - 亿位
- (folderName[1] - '0') * 1000000 + // 年 - 百万位
- (folderName[2] - '0') * 100000 + // 年 - 十万位
- (folderName[3] - '0') * 10000 + // 年 - 万位
- (folderName[5] - '0') * 1000 + // 月 - 千位
- (folderName[6] - '0') * 100 + // 月 - 百位
- (folderName[8] - '0') * 10 + // 日 - 十位
- (folderName[9] - '0'); // 日 - 个位
- }
- // 删除最旧的文件夹
- void deleteOldestFolder()
- {
- char resultBuf[MAX_DIR_NAME_LEN];
- char * p;
- char oldestFolder[32] = {0}; // 使用固定缓冲区
- uint32_t oldestTimestamp = UINT32_MAX; // 初始化为最大时间值
- bool found = false;
- #ifdef DEBUG
- Serial.println("开始查找最旧文件夹...");
- #endif
- memset(resultBuf,0,sizeof(resultBuf));
- // 重置目录遍历
- int dirResult = fs.readDir(fs.getRootPath(), resultBuf, sizeof(resultBuf));
-
- if (dirResult != 0)
- {
- Serial.println("错误: 无法读取根目录");
- return;
- }
- p = resultBuf;
- while (strlen(p) > 0)
- {
- #ifdef DEBUG
- printf("%s\r\n", p);
- #endif
- // 尝试解析文件夹名中的时间戳 (格式: YYYY-MM-DD)
- uint32_t folderTimestamp = parseFolderTimestamp(p);
-
- if (folderTimestamp == 0)
- {
- Serial.println("警告: 文件夹名格式错误,跳过");
- //读取下一个文件夹
- p += strlen(p) + 1;
- continue;
- }
- #ifdef DEBUG
- Serial.print("文件夹时间戳: ");
- Serial.println(folderTimestamp);
- #endif
- // 比较并记录最旧文件夹
- if (folderTimestamp < oldestTimestamp)
- {
- oldestTimestamp = folderTimestamp;
- strncpy(oldestFolder, p, strlen(p) - 1); //copy最旧的文件夹
- oldestFolder[sizeof(oldestFolder) - 1] = '\0'; // 确保终止
- found = true;
- #ifdef DEBUG
- Serial.print("更新最旧文件夹为: ");
- Serial.println(oldestFolder);
- #endif
- }
- //读取下一个文件夹
- p += strlen(p) + 1;
- }
-
- // 检查是否找到最旧文件夹
- if (found)
- {
- #ifdef DEBUG
- Serial.print("确定删除最旧文件夹: ");
- Serial.println(oldestFolder);
- #endif
- // 递归删除目录内容
- deleteRecursive(oldestFolder);
- }
- else
- {
- Serial.println("警告: 未找到符合条件的文件夹");
- }
- }
- // 递归删除目录及其内容
- void deleteRecursive(const char *path)
- {
- #ifdef DEBUG
- Serial.print("开始删除: ");
- Serial.println(path);
- #endif
- const int BUF_SIZE = 256; // 足够大的路径缓冲区
- char resultBuf[1584]; // 目录条目缓冲区
- char fullPath[BUF_SIZE]; // 完整路径缓冲区
-
- // 打开目标目录
- int dirResult = fs.readDir((char*)path, resultBuf, sizeof(resultBuf));
-
- if (dirResult != 0) {
- Serial.println("错误: 无法打开目录");
- return;
- }
- char *p = resultBuf;
- // 处理目录中的所有条目
- while (strlen(p) > 0)
- {
- // 跳过当前目录和上级目录
- if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) {
- p += strlen(p) + 1;
- continue;
- }
-
- // 安全构建完整路径
- int pathLen = snprintf(fullPath, BUF_SIZE, "%s/%s", path, p);
-
- // 检查路径长度是否溢出
- if (pathLen >= BUF_SIZE || pathLen < 0) {
- Serial.print("路径过长,跳过: ");
- Serial.println(p);
- p += strlen(p) + 1;
- continue;
- }
- #ifdef DEBUG
- Serial.print("处理: ");
- Serial.println(fullPath);
- #endif
- // 判断是否为目录
- if (fs.isDir(fullPath)) {
- // 递归删除子目录
- deleteRecursive(fullPath);
- } else {
- // 删除文件
- if (fs.remove(fullPath)) {
- Serial.println("文件删除成功");
- } else {
- Serial.println("文件删除失败");
- }
- }
-
- // 读取下一个条目
- p += strlen(p) + 1;
- }
- #ifdef DEBUG
- // 删除当前空目录
- Serial.print("删除空目录: ");
- Serial.println(path);
- #endif
- if (fs.rmdir(path)) {
- Serial.println("目录删除成功");
- } else {
- Serial.println("目录删除失败");
- }
- }
复制代码 |