5. fat文件系统
FatFs是一个通用的文件系统,SDK的FAT文件系统驱动包含完整FAT驱动、简易FAT驱动(Simple_FAT)两种,区别如表格所示”FAT文件系统简易驱动 & FAT文件系统完整驱动区别”;两种FAT驱动均不支持对sector大小大于512byte的FAT文件系统进行写操作,读操作正常;Simple_FAT为FAT裁切版,只能通过路径打开文件和读文件接口;完整FAT文件系统驱动能使用的接口如下图所示:![]()
图1.3 fat文件系统支持的接口
5.1. FAT文件系统管理函数
下面的函数为仅FAT使用的接口,在app/bsp/common/fs/fat/fat_resource.c中的fat_demo()接口,可以找到下列函数的使用示例;
5.1.1. 函数int fs_ftell(void *pvfile, void *parm)
此函数实现获取文件读写指针,仅FAT可使用该功能。其中参数:
1、pvfile:已打开的文件句柄; 2、param:用于保存文件系统读写指针; 3、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.2. 函数int vfs_get_fsize(void *pvfile, void *parm)
此函数实现获取文件大小,仅FAT可使用该功能。其中参数:
1、pvfile:已打开的文件句柄; 2、param:用于保存文件大小的指针; 3、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.3. 函数struct vfscan *vfs_fscan_new(void *pvfs, const char *path, const char *arg, u8 max_deepth, int (*callback)(void), strcut vfscan *fsn, struct vfscan_reset_info *info)
此函数实现FAT文件系统的文件扫描配置,会返回文件扫描句柄供其他扫描接口使用,与vfs_fscan_release()搭配调用,可在ac104n sdk中的play_file.c中查看该函数具体使用示例。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、path:文件扫描的起始路径; 3、arg:文件扫描配置参数; 例:static const char scan_parm_test[] = “-t” “MP1MP2MP3WAVTXT” “ -sn -r” ; ① 首行”-t”表示需要扫描的文件类型,后面”MP1MP2MP3WAVTXT”即为扫描的后缀名,三个字符为一种类型,最多不可超过20种文件类型; ② 第三行” -sn”表示扫描文件的顺序是按照文件号排序,另一种组合” -st”表示按照时间排序; ③ 第三行” -r”表示搜索会包含文件夹子目录; ④ 各种扫描参数配置间,需要以空格隔开,其他配置有: a)扫描是否将文件夹算入总数,可配置” -d”; b)扫描只读文件配置” -ar”,扫描非读文件配置” -a/r”,不配置默认扫描所有文件; 4、max_deep:扫描深度,最大为8; 5、callback:扫描回调; 6、fsn:文件扫描句柄; 7、info:扫描结果信息,包含文件总数和文件夹总数等信息; 8、返回值: 成功 返回文件扫描句柄; 失败 错误请查看errno-base.h。
5.1.4. 函数void fs_fscan_release(void *pvfs, struct vfscan *fs)
此函数实现释放文件扫描句柄,仅FAT可使用该功能,与vfs_fscan()搭配调用。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、fs:文件扫描句柄; 3、返回值:无。
5.1.5. 函数int fs_get_folderinfo(void **pvfile, struct vfscan *fs, int *start_num, int *end_num)
此函数实现文件夹扫描,需使用vfs_fscan()返回的文件扫描句柄,仅FAT可使用该功能。其中参数:
1、pvfile:需要扫描的设备里的文件; 2、fs:文件扫描句柄; 3、Start_num:用于保存第一个文件夹的第一个文件号; 4、End_num:用于保存最后一个文件夹的最后一个文件号; 5、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.6. 函数int fs_get_encfolder_info(void *pvfs, char *folder, char *ext, u32 *last_num, u32 *total_num)
此函数实现获取录音文件夹信息,包括录音文件总数,仅FAT可使用该功能。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、folder:文件夹路径,如”/JL_REC”; 3、ext:录音文件的后缀名,如”MP3”; 4、last_num:第一个可以使用的录音文件的文件序号; 5、total_num:总录音文件数; 6、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.7. 函数u32 vfs_file_name(void *pvfile, void *name, u32 len)
此函数实现获取文件的名字。该函数在获取文件名小于16byte(带后缀名)时,返回的为u8字符;在获取大于16byte(带后缀名)时,返回的是unicode码,且不会返回完整的文件名。具体需要获取文件长名并最终转化为u8字符进行打印出来,可参考该issue步骤:1、pvfile:已打开的文件句柄; 2、name:获取文件名指针。 3、len:获取文件名长度。 4、返回值:文件名长度;
5.1.8. 函数int fs_select(void *pvfs, void **ppvfile, struct vfscan *fs, int sel_mode, int arg)
此函数实现FAT文件系统的文件查找,支持多种查找方式,具体示例可查看fat_demo(void)接口。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、ppvfile:文件句柄指针,若句柄指向为NULL,函数会自行申请空间; 3、fs:文件扫描句柄; 4、sel_mode:文件查找方式: ① FSEL_BY_NUMBER:按文件号查找; ② FSEL_BY_SCLUST:按簇号查找; ③ FSEL_BY_PATH:按路径查找; 5、arg:文件查找参数; ① 按文件号查找时传入文件号; ② 按簇号查找时传入簇号; ③ 按路径查找时传入相应路径,支持通配符查找; 6、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.9. 函数int vfs_mk_dir(void *pvfs, char *folder, u8 mode)
此函数实现获取创建文件夹,仅FAT可使用该功能。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、folder:文件夹路径,如”/JL_REC”; 3、mode:目录属性; 1:设置为隐藏属性; 0:不设置; 4、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.10. 函数int vfs_delete_dir(void *pvfs, char *path)
此函数实现获取删除文件夹,仅FAT可使用该功能。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、path:文件夹路径,如”/JL_REC”; 3、返回值: 成功 0; 失败 错误请查看errno-base.h。使用demo:
log_info("vfs_delete_dir\n"); err = vfs_delete_dir(pvfs, "/test_dir/adir"); if (err != 0) { log_error("vfs_delet_dir 0x%x\n", err); goto __vfs_delete_fs_close; }
5.1.11. 函数int vfs_get_encfolder_info(void *pvfs, char *folder, char *ext, u32 *last_num, u32 *total_num)
此函数实现获取录音文件夹信息,包括录音文件总数,仅FAT可使用该功能。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、folder:文件夹路径,如”/JL_REC”; 3、ext:录音文件的后缀名,如”MP3”; 4、last_num:第一个可以使用的录音文件的文件序号; 5、total_num:总录音文件数; 6、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.12. 函数u32 vfs_file_delete(void *pvfile)
此函数实现文件的删除,仅FAT可使用该功能。其中参数:
1、pvfile:已打开的文件句柄; 2、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.13. 函数int vfs_select(void *pvfs, void **ppvfile, struct vfscan *fs, int sel_mode, int arg)
此函数实现FAT文件系统的文件查找,支持多种查找方式,具体示例可查看fat_demo(void)接口。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、ppvfile:文件句柄指针,若句柄指向为NULL,函数会自行申请空间; 3、fs:文件扫描句柄; 4、sel_mode:文件查找方式: ① FSEL_BY_NUMBER:按文件号查找; ② FSEL_BY_SCLUST:按簇号查找; ③ FSEL_BY_PATH:按路径查找; 5、arg:文件查找参数; ① 按文件号查找时传入文件号; ② 按簇号查找时传入簇号; ③ 按路径查找时传入相应路径,支持通配符查找; 6、返回值: 成功 0; 失败 错误请查看errno-base.h。
5.1.14. 函数int vfs_ioctl(void *pfile, int cmd, int arg)
fat文件系统支持多种命令操作,CMD命令如下:
1. 创建文件夹 FS_IOCTL_MK_DIR 2. 获取文件夹序号和文件夹内文件数目 FS_IOCTL_GET_FOLDER_INFO_3 3. 获取录音文件信息 FS_IOCTL_GET_ENCFOLDER_INFO 4. 重置扫描句柄 FS_IOCTL_RESET_VFSCAN 5. 设置卷标 FS_IOCTL_SET_VOL 6. 获取分区信息,簇大小,容量 FS_IOCTL_GET_PARTITION_INFO 7. 获取剩余空间 FS_IOCTL_GET_FREE_SPACE 8. 获取当前文件的相对路径和绝对路径 FS_IOCTL_GET_PATH 9.获取文件系统总容量 FS_IOCTL_GET_PARTITION_INFO 10.获取文件系统剩余容量 FS_IOCTL_GET_FREE_SPACE获取获取当前文件的相对路径和绝对路径demo:
len = vfs_fget_path(pfile, fsn, (u8 *)name, sizeof(name), 0); //获取绝对路径 len = vfs_fget_path(pfile, fsn, (u8 *)name, sizeof(name), 1); //获取相对路径 /*如果路径里的文件夹大于16byte,获取出来的是Unicode码,小于16byte的则为utf8*/ /*返回值为路径长度,name即为获取的路径*/获取剩余空间demo:
u32 cap = 0; res = vfs_ioctl(pvfs, (int)FS_IOCTL_GET_FREE_SPACE, (int)&cap); log_info("cap 0x%x\n",res,cap); //cap为获取到fat文件系统的剩余容量,单位为k获取分区信息,簇大小,容量demo:
u32 res = 0; FS_PARTITION_INFO part_info = {0}; res = vfs_ioctl(pvfs, (int)FS_IOCTL_GET_PARTITION_INFO, (int)&part_info); log_info("0x%x 0x%x 0x%x \n",part_info.clust_size,part_info.total_size, part_info.fs_type); /*分别对应簇大小,文件系统总容量大小,文件系统类型*/
5.1.14.1. 函数vfs_ioctl获取总容量命令 FS_IOCTL_GET_PARTITION_INFO
获取文件系统总容量,仅fat有效,参考代码:
1FS_PARTITION_INFO f_info;
2u32 err = vfs_ioctl(pvfile,FS_IOCTL_GET_PARTITION_INFO,(u32)&(f_info))
3if(0 != err)
4{
5 // succeed
6}
5.1.14.2. 函数vfs_ioctl获取剩余容量命令 FS_IOCTL_GET_FREE_SPACE
获取文件系统剩余容量,仅fat有效,参考代码:
1u32 free_apacity_Kbyte;//
2u32 err = vfs_ioctl(pvfile,FS_IOCTL_GET_PARTITION_INFO,(u32)&free_apacity_Kbyte);
3if(0 != err)
4{
5 // succeed
6}
5.1.15. 文件夹删除函数int vfs_delete_dir(void *pvfs, char *path)
此函数实现FAT文件系统的文件夹删除处理。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、path:需要删除的文件夹的路径; 成功 0; 失败 错误请查看errno-base.h。
5.1.16. 格式化接口 int vfs_format(void **ppvfs, const char *dev_name, const char *type, u32 clust_size, u8 create_new)
int vfs_format(void **ppvfs, const char *dev_name, const char *type, u32 clust_size, u8 create_new);此函数用于格式化存储设备并创建文件系统。
重要
重要警告
格式化操作会**永久删除**设备上的所有数据! 请确保已备份重要数据后再调用此函数。
5.1.16.1. 参数说明
ppvfs
备注
特殊行为
类型:
void **描述: 指向VFS指针的指针
格式化操作会释放当前的VFS指针:
格式化后,
*ppvfs会被设置为NULL需要重新调用
vfs_mount()获取新的VFS指针如果传入
ppvfs == NULL,必须指定有效的clust_size示例:
void *pvfs = NULL; // 格式化前获取VFS指针 vfs_mount(&pvfs, "sd0", "fat"); // 格式化操作 vfs_format(&pvfs, "sd0", "fat", 4*1024, 0); // 此时 pvfs == NULL,需要重新挂载
- dev_name
类型:
const char *描述: 设备名称
取值示例:
"sd0"- SD卡设备"udisk0"- USB存储设备"ext_flsh"- 外部数据Flash设备
备注
设备可用性
调用前需确保设备已正确连接并识别。
- type
类型:
const char *描述: 文件系统类型
取值范围:
"fat"- FAT文件系统(自动识别为FAT12、FAT16、FAT32)
小心
兼容性
不支持exfat。
- clust_size
类型:
u32描述: 簇大小(字节)
取值范围:
值
含义
备注
0
使用原簇大小
create_new = 0时使用1 * 512
512B簇
适合小文件(flash设备优选)
2 * 512
1KB簇
适合小文件(flash设备优选)
4 * 1024
4KB簇
适合小文件(flash设备优选)
8 * 1024
8KB簇
通用选择
16 * 1024
16KB簇
适合大文件
32 * 1024
32KB簇
适合大容量存储
64 * 1024
64KB簇
适合超大容量存储
重要
约束条件
当
create_new = 1时, 不能 填0一般设备建议值:4KB、8KB、16KB、32KB、64KB
flash建议值:512B、1KB、4KB
簇大小影响存储效率和性能
- create_new
类型:
u8描述: 创建模式
取值:
值
含义
使用场景
0
维持原文件系统类型
设备已有文件系统,仅重新格式化
1
新建文件系统类型
设备无文件系统 或需要更换类型
备注
使用场景判断
何时使用 create_new = 1:
新设备首次使用
完全重新组织设备内文件系统的数据结构
设备文件系统损坏无法识别
何时使用 create_new = 0:
设备已有文件系统,仅需要清空数据
定期维护性格式化
修复文件系统错误
5.1.16.2. 返回值
返回值
含义
0
成功
非0(FRESULT or -1)
失败
5.1.16.3. 注意事项
警告
数据安全
格式化会永久删除所有数据!
建议的操作流程:
📋 备份重要数据
🔍 确认设备名称正确
⚙️ 选择合适的簇大小
⚡ 执行格式化
🔄 重新挂载设备
备注
VFS指针管理
输入时:
*ppvfs指向当前的VFS结构过程中: 函数会释放该VFS结构
输出时:
*ppvfs被设置为NULL后续: 必须调用
vfs_mount()重新获取
小心
参数约束
create_new 和 clust_size 的组合规则:
create_new |
clust_size |
是否有效 |
|---|---|---|
0 |
0 |
✅ 有效(使用原簇大小) |
0 |
>0 |
⚠️ 可能无效(忽略新大小?) |
1 |
0 |
❌ 无效(必须指定大小) |
1 |
>0 |
✅ 有效 |
5.1.16.4. 常见问题
Q: 格式化后为什么需要重新挂载?
- A: 格式化会创建新的文件系统结构,原有的VFS上下文已失效。
必须重新挂载以建立新的文件系统连接。
Q: 可以边使用设备边格式化吗?
A: 绝对不行! 格式化前必须确保:
所有文件已关闭
设备未在被其他进程使用
已卸载设备(如果之前已挂载)
Q: 如何确定合适的簇大小?
A: 考虑以下因素:
存储设备容量:大容量设备可用较大簇
文件平均大小:小文件多用小簇
性能需求:大簇读写性能更好
空间效率:小簇空间浪费少
5.2. FAT文件系统简易驱动 & FAT文件系统完整驱动区别
简易FAT文件系统驱动
完整FAT文件系统驱动
FAT12 读
×
√
FAT16 读
×
√
FAT32 读
√
√
EXFAT 读
×
√
FAT12 写
×
√
FAT16 写
×
√
FAT32 写
×
√
EXFAT 写
×
√
盘扫描
×
√
长文件名
×
√
短文件名
√
√