为 ESP32 解锁跨平台存储识别能力:支持 FAT、NTFS、EXT4、APFS 的轻量级 BlockFS 组件
- 📦 blockfs
- ✅ 支持功能
- 📐 接口定义
blockfs_reader_t
blockfs_detect()
- 参数说明:
- 📌 示例用法
- ✅ 使用 SDMMC 卡(C 示例)
- ✅ 使用 USB SCSI MSC 设备(C 示例)
- 📁 文件结构
- 🚀 完整代码
- 📁
blockfs.h
- 📁
blockfs.c
- 📁
CMakeLists.txt
- 📁
- 🧩 集成方式(CMake)
- 📝 文件系统类型定义
- 📣 注意事项
- 🧪 测试平台
- 📜 License
📦 blockfs
blockfs
是一个轻量级文件系统识别组件,适用于 ESP32 平台,用于探测连接的块设备(如 SD 卡 或 USB 存储设备)上的文件系统类型(如 FAT32、NTFS、EXT4、APFS 等)。
组件采用 纯 C 接口,可直接集成到基于 main.c
的项目中,不依赖 C++ 调用。
✅ 支持功能
-
自动识别以下文件系统类型:
- FAT16 / FAT32
- NTFS
- EXT4
- APFS
-
支持以下块设备来源:
- 📀 SDMMC(原生 SD 卡接口)
- 💽 USB SCSI(通过 TinyUSB MSC 接口)
📐 接口定义
blockfs_reader_t
统一的块设备读取抽象:
typedef struct {void* context;esp_err_t (*read)(void* context, void* buffer, uint32_t sector, uint32_t count);uint32_t sector_size;
} blockfs_reader_t;
blockfs_detect()
核心函数,用于识别设备上的文件系统类型:
esp_err_t blockfs_detect(const blockfs_reader_t* reader, blockfs_type_t* out_type);
参数说明:
reader
:你构造的读取器对象,封装底层块设备out_type
:输出文件系统类型(BLOCKFS_FAT
/BLOCKFS_EXT4
等)
📌 示例用法
✅ 使用 SDMMC 卡(C 示例)
#include "blockfs.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"static esp_err_t sdmmc_read_cb(void* ctx, void* buffer, uint32_t sector, uint32_t count) {return sdmmc_read_sectors((sdmmc_card_t*)ctx, buffer, sector, count);
}static const char* fs_type_str(blockfs_type_t type) {switch (type) {case BLOCKFS_FAT: return "FAT";case BLOCKFS_NTFS: return "NTFS";case BLOCKFS_EXT4: return "EXT4";case BLOCKFS_APFS: return "APFS";default: return "Unknown";}
}void detect_sdcard(sdmmc_card_t* card) {blockfs_reader_t reader = {.context = card,.read = sdmmc_read_cb,.sector_size = 512};blockfs_type_t type;if (blockfs_detect(&reader, &type) == ESP_OK) {printf("Filesystem: %s\n", fs_type_str(type));}
}
✅ 使用 USB SCSI MSC 设备(C 示例)
#include "blockfs.h"
#include "esp_private/msc_scsi_bot.h"static esp_err_t scsi_read_cb(void* ctx, void* buffer, uint32_t sector, uint32_t count) {msc_host_device_handle_t dev = (msc_host_device_handle_t)ctx;return scsi_cmd_read10(dev, buffer, sector, count, 512); // sector_size 传入
}static const char* fs_type_str(blockfs_type_t type) {switch (type) {case BLOCKFS_FAT: return "FAT";case BLOCKFS_NTFS: return "NTFS";case BLOCKFS_EXT4: return "EXT4";case BLOCKFS_APFS: return "APFS";default: return "Unknown";}
}void detect_usb_device(msc_host_device_handle_t dev) {blockfs_reader_t reader = {.context = dev,.read = scsi_read_cb,.sector_size = 512};blockfs_type_t type;if (blockfs_detect(&reader, &type) == ESP_OK) {printf("Filesystem: %s\n", fs_type_str(type));}
}
📁 文件结构
blockfs/
├── include/
│ └── blockfs.h // C 接口头文件
├── src/
│ └── blockfs.c // 文件系统检测逻辑(C)
├── CMakeLists.txt
🚀 完整代码
📁 blockfs.h
#pragma once#include "esp_err.h"
#include <stdint.h>
#include <stddef.h>#ifdef __cplusplus
extern "C" {
#endiftypedef enum {BLOCKFS_UNKNOWN = 0,BLOCKFS_FAT,BLOCKFS_NTFS,BLOCKFS_EXT4,BLOCKFS_APFS
} blockfs_type_t;// C 风格块设备读取接口
typedef struct {void* context;esp_err_t (*read)(void* context, void* buffer, uint32_t sector, uint32_t count);uint32_t sector_size;
} blockfs_reader_t;// 文件系统识别函数
esp_err_t blockfs_detect(const blockfs_reader_t* reader, blockfs_type_t* out_type);#ifdef __cplusplus
}
#endif
📁 blockfs.c
#include "blockfs.h"
#include <string.h>
#include <stdbool.h>esp_err_t blockfs_detect(const blockfs_reader_t *reader, blockfs_type_t *out_type)
{if (!reader || !reader->read || !out_type){return ESP_ERR_INVALID_ARG;}uint8_t buffer[4096];const uint32_t sec_size = reader->sector_size;// 读取 LBA 0if (reader->read(reader->context, buffer, 0, 1) != ESP_OK){return ESP_FAIL;}bool is_mbr = (buffer[510] == 0x55 && buffer[511] == 0xAA);uint32_t fs_start = 0;if (is_mbr){uint8_t *entry = buffer + 446;if (entry[4] == 0xEE){// GPT: 检查 LBA 1 是否是 "EFI PART"if (reader->read(reader->context, buffer, 1, 1) != ESP_OK)return ESP_FAIL;if (memcmp(buffer, "EFI PART", 8) != 0)return ESP_FAIL;// 读取 GPT 第一个分区项(LBA 2)if (reader->read(reader->context, buffer, 2, 1) != ESP_OK)return ESP_FAIL;const uint8_t apfs_guid[16] = {0xEF, 0x57, 0x34, 0x7C,0x00, 0x00,0xAA, 0x11,0xAA, 0x11,0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};// 比较 GPT 分区类型 GUID(前16字节)if (memcmp(buffer, apfs_guid, 16) == 0){*out_type = BLOCKFS_APFS;return ESP_OK;}// 如果不是 APFS,继续取分区起始位置(GPT 分区项中的 First LBA)fs_start = *(uint64_t *)(buffer + 32);}else{fs_start = *(uint32_t *)(entry + 8); // MBR 第一个分区的起始 LBA}}else{fs_start = 0; // 无分区,直接是文件系统}// 读取文件系统头if (reader->read(reader->context, buffer, fs_start, 8) != ESP_OK){return ESP_FAIL;}// 检测 FATif (memcmp(buffer + 0x52, "FAT32", 5) == 0 || memcmp(buffer + 0x36, "FAT16", 5) == 0){*out_type = BLOCKFS_FAT;return ESP_OK;}// 检测 NTFSif (memcmp(buffer + 3, "NTFS", 4) == 0){*out_type = BLOCKFS_NTFS;return ESP_OK;}// 检测 EXT4(超级块在 1080 字节处)uint32_t ext4_offset = 1080 % sec_size;uint32_t ext4_sector = fs_start + (1080 / sec_size);if (reader->read(reader->context, buffer, ext4_sector, 1) == ESP_OK){if (buffer[ext4_offset] == 0x53 && buffer[ext4_offset + 1] == 0xEF){*out_type = BLOCKFS_EXT4;return ESP_OK;}}*out_type = BLOCKFS_UNKNOWN;return ESP_OK;
}
📁 CMakeLists.txt
idf_component_register(SRCS "src/blockfs.c"INCLUDE_DIRS "include"REQUIRES sdmmc usb_host_msc # 可选
)
🧩 集成方式(CMake)
在你的主工程 CMakeLists.txt
添加:
set(EXTRA_COMPONENT_DIRS path/to/blockfs)
或将 blockfs
放入 components/
目录,自动扫描。
📝 文件系统类型定义
typedef enum {BLOCKFS_UNKNOWN = 0,BLOCKFS_FAT,BLOCKFS_NTFS,BLOCKFS_EXT4,BLOCKFS_APFS
} blockfs_type_t;
📣 注意事项
- 不挂载文件系统:
blockfs
仅识别类型,不挂载。挂载请使用 ESP-IDF 的esp_vfs_fat
或 ext4/littlefs 等组件。 - 分区支持:自动识别 MBR / GPT 分区,提取第一个有效分区进行分析。
- 需 512 字节扇区设备:部分设备可能使用其他扇区大小(需确认传入正确
sector_size
)
🧪 测试平台
- ESP32 / ESP32-S3 / ESP32-P4
- SDMMC 卡、USB MSC 存储
- FAT32/EXT4/NTFS/APFS U 盘和 TF 卡
📜 License
MIT License