4、ELM FatFS 文件系统:FatFS 简介、FatFS 配置选项、长文件名支持、扇区大小配置
4.1 FatFS 到底是什么?
说实话,很多刚接触 RT-Thread 的朋友,一听到「文件系统」就觉得很高深。其实没那么玄乎。
FatFS,全称是 ELM ChaN 开发的 FatFs 模块。它是一个轻量级的 FAT 文件系统实现。说白了,就是让嵌入式设备能像电脑一样,在 SD 卡、Flash 或者 SPI Flash 上读写文件。
我个人习惯把 FatFS 比作「嵌入式世界的文件管家」。你不需要关心底层存储介质怎么操作,只需要调用 f_open、f_read、f_write 这些 API 就行了。
我在项目中遇到过好几次,有人觉得文件系统是「标配」,随便选一个就行。其实不然。FatFS 之所以在 RT-Thread 里被广泛使用,是因为它有几个硬核优点:
- 代码量极小——完整版也就几十 KB,裁剪后更小
- 移植性极强——只要实现底层读写接口就行
- 兼容性好——Windows、Linux 都能直接读写
核心要点:FatFS 不是 RT-Thread 独有的,它是一个独立开源项目。RT-Thread 只是把它集成到了 DFS(Device File System)框架里。你完全可以在裸机上直接用 FatFS。
4.2 FatFS 配置选项——别被吓到
打开 ffconf.h 这个文件,你可能会看到一堆宏定义。我第一次看的时候也头大。但别慌,真正需要你动手改的,其实就几个。
我建议你重点关注这几个配置项:
| 配置宏 | 默认值 | 说明 | 我的建议 |
|---|---|---|---|
FF_FS_READONLY |
0 | 是否只读 | 保持 0,除非你确定只读 |
FF_FS_MINIMIZE |
0 | 功能裁剪等级 | 0 为全功能,资源紧张可设 1 或 2 |
FF_USE_STRFUNC |
0 | 字符串函数支持 | 建议设为 1,方便调试 |
FF_USE_MKFS |
0 | 格式化功能 | 建议设为 1,产品中很有用 |
FF_USE_FASTSEEK |
0 | 快速定位 | 大文件操作时建议开启 |
小技巧:如果你在 RT-Thread 的 menuconfig 里配置,这些选项会自动映射到 ffconf.h。我个人习惯直接改 ffconf.h,因为更直观。但用 menuconfig 的好处是不会改错格式。
4.3 长文件名支持——踩过的坑
嗯,这里要重点说说长文件名。FatFS 默认只支持 8.3 格式的短文件名(比如 HELLO.TXT)。但现在的产品,谁还用这种命名方式?
要支持长文件名,你需要配置 FF_USE_LFN 这个宏。它有几种模式:
- 0:不支持长文件名(默认)
- 1:使用静态缓冲区(不可重入)
- 2:使用栈上动态缓冲区(可重入,但栈要大)
- 3:使用堆上动态缓冲区(推荐,但需要
ff_memalloc)
我曾经在一个项目里,因为偷懒没开长文件名支持,结果客户反馈说「为什么我拷进去的 2024_annual_report_v2_final_final.xlsx 打不开?」——你想想看,文件名被截断成 2024_AN~1.XLS,能不乱吗?
我建议你:
- 如果 RAM 够用,直接设
FF_USE_LFN = 3,配合FF_LFN_BUF = 255 - 如果 RAM 紧张,设
FF_USE_LFN = 2,但记得把任务栈加大到 1024 以上 - 千万别设 1——除非你只有一个线程操作文件系统
注意:开启长文件名后,FILINFO 结构体的大小会变大。如果你用 f_stat 或 f_readdir,记得给 fno 分配足够的空间。我见过有人在这里踩坑,导致内存越界。
4.4 扇区大小配置——别小看这个参数
扇区大小,对应 FatFS 里的 FF_MIN_SS 和 FF_MAX_SS。这两个参数决定了文件系统能识别的扇区范围。
常见的扇区大小有:
- 512 字节——传统 SD 卡、NAND Flash 的标配
- 1024 字节——某些 SPI Flash 的默认值
- 4096 字节——高级 SD 卡、eMMC 的常见值
我记得有一次,客户拿了一块 4K 扇区的 SD 卡过来,说「读写总是报错」。我一看配置,FF_MAX_SS 还是默认的 512。改到 4096 后,问题立刻解决。
这里有个经验:
- 如果你只用 SD 卡,设
FF_MIN_SS = 512,FF_MAX_SS = 512就够了 - 如果你要兼容多种存储介质,设
FF_MIN_SS = 512,FF_MAX_SS = 4096 - 注意:
FF_MAX_SS越大,FatFS 内部缓冲区也越大,RAM 消耗会增多
避坑指南:我曾经在一个项目里,把 FF_MAX_SS 设成了 4096,但底层驱动只支持 512 字节读写。结果文件系统初始化没问题,一读写就崩溃。所以,扇区大小配置必须和底层驱动保持一致。
4.5 实战建议——怎么配最省心
如果你问我,一个通用配置长什么样?我会给你这个参考:
// ffconf.h 关键配置
#define FF_FS_READONLY 0 // 可读写
#define FF_FS_MINIMIZE 0 // 全功能
#define FF_USE_STRFUNC 1 // 支持字符串函数
#define FF_USE_MKFS 1 // 支持格式化
#define FF_USE_FASTSEEK 1 // 支持快速定位
#define FF_USE_LFN 3 // 长文件名,堆分配
#define FF_LFN_UNICODE 0 // 非 Unicode(用 ANSI)
#define FF_LFN_BUF 255 // 长文件名最大长度
#define FF_MIN_SS 512 // 最小扇区
#define FF_MAX_SS 4096 // 最大扇区
#define FF_USE_TRIM 1 // 支持 TRIM(延长 Flash 寿命)
这个配置在大多数场景下都能跑。当然,如果你的 RAM 只有几十 KB,那就要适当裁剪了。
最后说一句:配置完记得重新编译,别只改了文件就以为生效了。我刚开始也犯过这种低级错误,哈哈。