// // Created by misaki on 2025/9/9. // #include "SDFileManager.h" #include "SD_MMC.h" #include #include #include #include SDFileManager* SDFileManager::SDFileInstance = nullptr; std::mutex SDFileManager::instance_mutex; SDFileManager *SDFileManager::getInstance() { // 双检锁(DCLP),C++11 起 atomic+mutex 组合保证线程安全 SDFileManager* tmp = SDFileInstance; if (tmp == nullptr) { std::lock_guard lock(instance_mutex); tmp = SDFileInstance; if (tmp == nullptr) { tmp = new SDFileManager(); SDFileInstance = tmp; } } return tmp; } SDFileManager::SDFileManager() : is_initialized(false), current_directory(MOUNT_POINT) { // 初始化SD卡 init(); // 获取Flash大小 Flash_Searching(); } SDFileManager::~SDFileManager() { // 清理资源 } void SDFileManager::init() { SD_Init(); is_initialized = true; } void SDFileManager::tryInitSDCard() { ESP_LOGI("SDFileManager", "Trying to initialize SD card..."); } bool SDFileManager::writeFileSync(const char* path, const char* data, const size_t len, const char* type) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return false; } ESP_LOGI("SDFileManager", "Opening file %s", path); FILE *f = fopen(path, type); if (f == nullptr) { ESP_LOGE("SDFileManager", "Failed to open file for writing"); return ESP_FAIL; } const size_t written = fwrite(data, 1, len, f); fclose(f); if (written != len) { ESP_LOGE("SDFileManager", "Only %zu/%zu bytes written", written, len); return ESP_FAIL; } ESP_LOGI("SDFileManager", "File written (%zu bytes)", written); return true; } std::string SDFileManager::readFileSync(const char* path) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return ""; } FILE* file = fopen(path, "r"); if (file == nullptr) { ESP_LOGE("SDFileManager", "Failed to open file: %s", path); return ""; } // 获取文件大小 fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); // 读取文件内容 std::string content; content.resize(size); size_t bytes_read = fread(&content[0], 1, size, file); fclose(file); if (bytes_read != static_cast(size)) { ESP_LOGE("SDFileManager", "Failed to read entire file: %s", path); return ""; } return content; } std::string SDFileManager::readFileSync(const std::string& path) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return ""; } FILE* file = fopen(path.c_str(), "r"); if (file == nullptr) { ESP_LOGE("SDFileManager", "Failed to open file: %s", path.c_str()); return ""; } // 获取文件大小 fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); // 读取文件内容 std::string content; content.resize(size); size_t bytes_read = fread(&content[0], 1, size, file); fclose(file); if (bytes_read != static_cast(size)) { ESP_LOGE("SDFileManager", "Failed to read entire file: %s", path.c_str()); return ""; } return content; } std::vector SDFileManager::listFilesSync(const char* directory, const char* extension) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return {}; } constexpr int max_files = 50; char file_names[max_files][100]; const uint16_t file_count = Folder_retrieval(directory, extension, file_names, max_files); std::vector files; for (uint16_t i = 0; i < file_count; ++i) { files.emplace_back(file_names[i]); } return files; } FILE* SDFileManager::openFileSync(const char* path, const char* mode) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return nullptr; } return Open_File(path); } bool SDFileManager::closeFileSync(FILE* file) { if (file != nullptr) { return fclose(file) == 0; } return false; } void SDFileManager::asyncWriteFile(const char* path, const char* data, const size_t len, const char* type, WriteCallback callback) { ThreadConfig config = getThreadConfig("write_file"); ThreadManager::createThread(config, [this, path = std::string(path), data = std::string(data), callback, type, len]() { const bool success = this->writeFileSync(path.c_str(), data.c_str(), len, type); if (callback) { callback(success, path.c_str()); } }).detach(); // 分离线程,使其独立运行 } void SDFileManager::asyncReadFile(const char* path, ReadCallback callback) { if (!callback) { return; // 没有回调函数,异步读取无意义 } ThreadConfig config = getThreadConfig("read_file"); ThreadManager::createThread(config, [this, path = std::string(path), callback]() { std::string content = this->readFileSync(path.c_str()); bool success = !content.empty(); callback(success, path.c_str(), content); }).detach(); } void SDFileManager::asyncListFiles(const char* directory, const char* extension, ListCallback callback) { if (!callback) { return; // 没有回调函数,异步列出文件无意义 } ThreadConfig config = getThreadConfig("list_files"); ThreadManager::createThread(config, [this, directory = std::string(directory), extension = std::string(extension ? extension : ""), callback]() { std::vector files = this->listFilesSync( directory.c_str(), extension.empty() ? nullptr : extension.c_str() ); bool success = !files.empty(); callback(success, files); }).detach(); } void SDFileManager::asyncOpenFile(const char* path, const char* mode, OpenCallback callback) { if (!callback) { return; // 没有回调函数,异步打开文件无意义 } ThreadConfig config = getThreadConfig("open_file"); ThreadManager::createThread(config, [this, path = std::string(path), mode = std::string(mode), callback]() { FILE* file = this->openFileSync(path.c_str(), mode.c_str()); bool success = (file != nullptr); callback(success, file); }).detach(); } ThreadConfig SDFileManager::getThreadConfig(const char* operation) { ThreadConfig config; config.name = "sd_" + std::string(operation); config.core_id = -1; // 不绑定核心 config.stack_size = 4096; config.priority = 5; config.inherit_cfg = false; return config; } // 实现ls命令 std::string SDFileManager::lsCommand(const char* path, bool recursive, bool showDetails) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return "Error: SD card not initialized"; } std::string fullPath = path; if (fullPath.empty() || fullPath == ".") { fullPath = current_directory; } else if (fullPath[0] != '/') { // 相对路径 fullPath = current_directory + "/" + fullPath; } DIR* dir = opendir(fullPath.c_str()); if (dir == nullptr) { return "Error: Cannot open directory " + fullPath; } std::stringstream result; struct dirent* entry; struct stat st; result << "Directory listing for: " << fullPath << "\n"; result << "----------------------------------------\n"; while ((entry = readdir(dir)) != nullptr) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } std::string entryPath = fullPath + "/" + entry->d_name; if (stat(entryPath.c_str(), &st) != 0) { continue; } if (showDetails) { result << getFileInfoString(entry->d_name, &st); } else { result << entry->d_name; } if (S_ISDIR(st.st_mode)) { result << "/"; } result << "\n"; // 递归列出子目录 if (recursive && S_ISDIR(st.st_mode)) { std::string subDirResult = lsCommand(entryPath.c_str(), true, showDetails); result << subDirResult; } } closedir(dir); return result.str(); } // 实现cat命令 std::string SDFileManager::catCommand(const char* path, bool lineNumbers) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return "Error: SD card not initialized"; } std::string fullPath = path; if (fullPath[0] != '/') { // 相对路径 fullPath = current_directory + "/" + fullPath; } FILE* file = fopen(fullPath.c_str(), "r"); if (file == nullptr) { return "Error: Cannot open file " + fullPath; } std::stringstream result; char buffer[256]; int lineNumber = 1; while (fgets(buffer, sizeof(buffer), file) != nullptr) { if (lineNumbers) { result << std::setw(4) << lineNumber << ": "; } result << buffer; lineNumber++; } fclose(file); return result.str(); } // 实现pwd命令 std::string SDFileManager::pwdCommand() { return current_directory; } // 实现cd命令 bool SDFileManager::cdCommand(const char* path) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return false; } std::string newPath; if (path[0] == '/') { // 绝对路径 newPath = path; } else if (strcmp(path, "..") == 0) { // 上级目录 size_t pos = current_directory.find_last_of('/'); if (pos != std::string::npos && pos > 0) { newPath = current_directory.substr(0, pos); } else { newPath = "/"; } } else { // 相对路径 newPath = current_directory + "/" + path; } // 检查路径是否存在且是目录 struct stat st; if (stat(newPath.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) { return false; } current_directory = newPath; return true; } // 实现mkdir命令 bool SDFileManager::mkdirCommand(const char* path) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return false; } std::string fullPath = path; if (fullPath[0] != '/') { // 相对路径 fullPath = current_directory + "/" + fullPath; } // 创建目录 int result = mkdir(fullPath.c_str(), 0777); return result == 0; } // 实现rm命令 bool SDFileManager::rmCommand(const char* path, bool recursive) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return false; } std::string fullPath = path; if (fullPath[0] != '/') { // 相对路径 fullPath = current_directory + "/" + fullPath; } struct stat st; if (stat(fullPath.c_str(), &st) != 0) { return false; } if (S_ISDIR(st.st_mode)) { if (recursive) { return removeDirectoryRecursive(fullPath.c_str()); } else { // 非递归删除空目录 return rmdir(fullPath.c_str()) == 0; } } else { // 删除文件 return remove(fullPath.c_str()) == 0; } } // 实现stat命令 std::string SDFileManager::statCommand(const char* path) { std::lock_guard lock(file_operation_mutex); if (!is_initialized) { ESP_LOGE("SDFileManager", "SD card not initialized"); return "Error: SD card not initialized"; } std::string fullPath = path; if (fullPath[0] != '/') { // 相对路径 fullPath = current_directory + "/" + fullPath; } struct stat st; if (stat(fullPath.c_str(), &st) != 0) { return "Error: Cannot get file status for " + fullPath; } return getFileInfoString(fullPath.c_str(), &st); } // 辅助方法:递归删除目录 bool SDFileManager::removeDirectoryRecursive(const char* path) { DIR* dir = opendir(path); if (dir == nullptr) { return false; } struct dirent* entry; while ((entry = readdir(dir)) != nullptr) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } std::string entryPath = std::string(path) + "/" + entry->d_name; struct stat st; if (stat(entryPath.c_str(), &st) != 0) { continue; } if (S_ISDIR(st.st_mode)) { if (!removeDirectoryRecursive(entryPath.c_str())) { closedir(dir); return false; } } else { if (remove(entryPath.c_str()) != 0) { closedir(dir); return false; } } } closedir(dir); return rmdir(path) == 0; } // 辅助方法:获取文件信息字符串 std::string SDFileManager::getFileInfoString(const char* path, const struct stat* st) { std::stringstream info; // 文件类型和权限 info << getFileTypeString(st->st_mode); info << ((st->st_mode & S_IRUSR) ? "r" : "-"); info << ((st->st_mode & S_IWUSR) ? "w" : "-"); info << ((st->st_mode & S_IXUSR) ? "x" : "-"); info << ((st->st_mode & S_IRGRP) ? "r" : "-"); info << ((st->st_mode & S_IWGRP) ? "w" : "-"); info << ((st->st_mode & S_IXGRP) ? "x" : "-"); info << ((st->st_mode & S_IROTH) ? "r" : "-"); info << ((st->st_mode & S_IWOTH) ? "w" : "-"); info << ((st->st_mode & S_IXOTH) ? "x" : "-"); // 文件大小 info << " " << std::setw(10) << formatFileSize(st->st_size); // 最后修改时间 struct tm* timeinfo = localtime(&st->st_mtime); char timeBuf[20]; strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M", timeinfo); info << " " << timeBuf; // 文件名 info << " " << path; return info.str(); } // 辅助方法:获取文件类型字符串 std::string SDFileManager::getFileTypeString(mode_t mode) { if (S_ISREG(mode)) return "-"; // 普通文件 if (S_ISDIR(mode)) return "d"; // 目录 if (S_ISCHR(mode)) return "c"; // 字符设备 if (S_ISBLK(mode)) return "b"; // 块设备 if (S_ISFIFO(mode)) return "p"; // 管道 if (S_ISLNK(mode)) return "l"; // 符号链接 if (S_ISSOCK(mode)) return "s"; // 套接字 return "?"; // 未知类型 } // 辅助方法:格式化文件大小 std::string SDFileManager::formatFileSize(size_t size) { std::stringstream ss; if (size < 1024) { ss << size << " B"; } else if (size < 1024 * 1024) { ss << std::fixed << std::setprecision(1) << (size / 1024.0) << " KB"; } else if (size < 1024 * 1024 * 1024) { ss << std::fixed << std::setprecision(1) << (size / (1024.0 * 1024.0)) << " MB"; } else { ss << std::fixed << std::setprecision(1) << (size / (1024.0 * 1024.0 * 1024.0)) << " GB"; } return ss.str(); }