ESP32 Wrover开发板SD卡文件删除功能失效求助
ESP32 SD卡图片删除功能失效问题解决
问题概述
使用Freenove ESP32 Wrover开发板实现拍照并存储到SD卡的功能正常,但在setup中编写的删除SD卡所有图片的代码无法工作。串口输出显示所有文件都找不到,SD.exists()和SD.remove()始终返回0。
原代码
//Lib Esp32 #include "SD.h" #include "SPI.h" #include "esp_camera.h" #include "FS.h" // SD Card ESP32 #include "SD_MMC.h" // SD Card ESP32 #include "soc/soc.h" // Disable brownour problems #include "soc/rtc_cntl_reg.h" // Disable brownour problems #include "driver/rtc_io.h" #define EEPROM_SIZE 1 //Pins module Carte SD #define MOSI 14 #define MISO 32 #define CLK 13 #define SS 33 #define PWDN_GPIO_NUM -1 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 21 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 19 #define Y4_GPIO_NUM 18 #define Y3_GPIO_NUM 5 #define Y2_GPIO_NUM 4 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 camera_config_t config; File root; int fileCountOnSD = 0; // for counting files #define CAMERA_MODEL_WROVER_KIT void setup() { Serial.begin(115200); Serial.println(); Serial.println(); Serial.println("//------------Initialisation-------------//"); config_init(); if(psramFound()){ config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA config.jpeg_quality = 5; config.fb_count = 2; } else { config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 5; config.fb_count = 1; } // camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } sensor_t * s = esp_camera_sensor_get(); s->set_vflip(s, 1); //1-Upside down, 0-No operation s->set_hmirror(s, 0); //1-Reverse left and right, 0-No operation s->set_brightness(s, 1); //up the blightness just a bit s->set_saturation(s, -1); //lower the saturation //permet de définir les pins de la carte pour comm SPI SPI.begin(CLK, MISO, MOSI, SS); //on vérifie si module SD présent if(!SD.begin(SS)){ Serial.println("Card Mount Failed"); //return; } else{ Serial.println("Card Mount Ok"); } uint8_t cardType = SD.cardType(); if(cardType == CARD_NONE){ Serial.println("No SD card attached"); //return; } root = SD.open("/"); countingFiles(root, 0); // Now print the total files count Serial.println(F("fileCountOnSD: ")); Serial.println(fileCountOnSD); for(int i=1;i<=fileCountOnSD;i++){ String stringToDelete = "picture"+String(i)+".jpg"; if(SD.exists(stringToDelete.c_str())){ SD.remove(stringToDelete.c_str()); } else{ Serial.println("no file to remove"); } } countingFiles(root, 0); Serial.println("after remove : "); Serial.println(fileCountOnSD); Serial.println("done!"); Serial.println("//------------Fin Initialisation-------------//"); } void loop() { //partie caméra camera_fb_t * fb = NULL; fb = esp_camera_fb_get(); if(!fb) { Serial.println("Camera capture failed"); return; } else{ Serial.println("Camera capture ok"); fileCountOnSD++; String path = "/picture" + String(fileCountOnSD) +".jpg"; File file = SD.open(path.c_str(), FILE_WRITE); if(!file){ Serial.println("Failed to open file in writing mode"); } else { file.write(fb->buf, fb->len); // payload (image), payload length Serial.printf("Saved file to path: %s\n", path.c_str()); } file.close(); } esp_camera_fb_return(fb); //tempo d'1s delay(1000); } //Fonction d'initialisation de la caméra void config_init() { config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; config.fb_count = 1; } void countingFiles(File dir, int numTabs) { while (true) { File entry = dir.openNextFile(); if (! entry) { // no more files break; } // for each file count it fileCountOnSD++; } }
串口输出
22:55:10.433 -> //------------Initialisation-------------// 22:55:10.697 -> Card Mount Ok 22:55:17.256 -> fileCountOnSD: 22:55:17.256 -> 8 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.256 -> no file to remove 22:55:17.300 -> after remove : 22:55:17.300 -> 8 22:55:17.300 -> done!
问题原因与修复方案
1. 路径不匹配(核心问题)
拍照时保存文件使用的是绝对路径:/pictureX.jpg,但删除时使用的是相对路径pictureX.jpg。ESP32的SD库要求使用绝对路径才能正确定位根目录下的文件,相对路径会在当前工作目录(默认不是根目录)查找,导致找不到文件。
修复:修改删除循环中的路径字符串,添加根目录斜杠:
String stringToDelete = "/picture"+String(i)+".jpg";
2. 文件计数与遍历逻辑问题
- 原
countingFiles函数会统计所有条目(包括目录),导致fileCountOnSD数值不准确,可能包含非图片文件或目录。 - 第一次遍历
root后,文件指针已经移动到目录末尾,第二次调用countingFiles时不会重新遍历,导致计数不变。
修复:
- 重写
countingFiles函数,只统计文件(排除目录),并在每次统计前重置计数:
void countingFiles(File dir, int numTabs) { fileCountOnSD = 0; // 重置计数 while (true) { File entry = dir.openNextFile(); if (!entry) { break; } if(!entry.isDirectory()){ // 仅统计文件 fileCountOnSD++; } entry.close(); // 关闭文件句柄,避免资源泄漏 } }
- 第二次统计前重新打开根目录,重置文件指针:
root = SD.open("/"); // 重新打开根目录 countingFiles(root, 0);
3. 更可靠的删除逻辑(推荐)
依赖序号遍历删除的方式存在缺陷:如果SD卡上存在非连续命名的图片文件,或者有其他非图片文件,会导致漏删或误判。直接遍历所有文件并筛选.jpg后缀的文件删除更可靠:
// 替换原有的删除循环 root = SD.open("/"); while(true){ File entry = root.openNextFile(); if(!entry) break; if(!entry.isDirectory()){ String fileName = entry.name(); if(fileName.endsWith(".jpg")){ if(SD.remove(fileName)){ Serial.printf("Deleted: %s\n", fileName.c_str()); } else { Serial.printf("Failed to delete: %s\n", fileName.c_str()); } } } entry.close(); }
内容的提问来源于stack exchange,提问作者superneiluj
相关产品推荐
相关产品推荐

