2. 文件系统管理
支持的文件系统列表:
文件系统
详情
sydfs
只读文件系统,用于存放资源文件到norflash;
norfs
循环覆盖文件系统,可读写;针对norflash设计;
simple_fat
简单fat文件系统驱动,占用资源少,不支持搜索和多文件同时打开;支持FAT12/16/32, EXFAT;
fatfs
完整的fat文件系统驱动,占用资源多,支持搜索;支持FAT12/16/32, EXFAT;
各芯片SDK支持的文件系统类型如下:
芯片支持的设备
sydfs
norfs
simple_fat
fatfs
AD14N
√
√
√
AC104N
√
√
√
AD15N
√
AD17N
√
AD18N
√
√
√
- SDK中通过vfs来集中管理各类文件系统,涉及的文件目录包括:
app\bsp\common\fs目录下的所有c文件;
include_lib\fs目录下的所有h文件;
errno-base.h文件;
备注
- vfs有以下主要函数:
void vfs_init(void);
u32 vfs_mount(void **ppvfs, void *device, void *type);
u32 vfs_openbypath(void *pvfs, void **ppvfile, const char *path);
u32 vfs_openbyindex(void *pvfs, void **ppvfile, u32 index);
u32 vfs_createfile(void *pvfs, void **ppvfile, u32 *pindex);
u32 vfs_read(void *pvfile, void *buf, u32 len);
u32 vfs_write(void *pvfile, void *buf, u32 len);
u32 vfs_seek(void *pvfile, u32 offset, u32 mode);
u32 vfs_file_close(void **ppvfile);
u32 vfs_fs_close(void **ppvfs);
u32 vfs_file_name(void *pvfile, void *name, u32 len);
int vfs_get_attrs(void *pvfile, void *pvfs_attr);
int vfs_ioctl(void *pvfile, int cmd, int arg);
备注
其中,fatfs中独有的函数:
int vfs_ftell(void *pvfile, void *parm);
int vfs_get_fsize(void *pvfile, void *parm);
struct vfscan *vfs_fscan_new(void *pvfs, const char *path, const char *arg, u8 max_deepth, int (*callback)(void), struct vfscan *fsn, struct vfscan_reset_info *info);
int vfs_fscan_release(void *pvfs, struct vfscan *fs);
int vfs_select(void *pvfs, void **ppvfile, struct vfscan *fs, int sel_mode, int arg);
int vfs_get_folderinfo(void **pvfile, struct vfscan *fs, int *start_num, int *end_num);
int vfs_mk_dir(void *pvfs, char *folder, u8 mode);
int vfs_get_encfolder_info(void *pvfs, char *folder, char *ext, u32 *last_num, u32 *total_num);
int vfs_file_delete(void *pvfile);
2.1. 文件系统介绍
Sdk中默认支持的文件系统有:sydfs、norfs、fatfs(AC104,AD17,AD18)、simple_fatfs(AD14N);
可以在app\bsp\common\fs目录下查看各文件系统的文件以及支持的接口;
本小节将介绍各个文件系统以及支持的ioctl对应的cmd命令:
2.1.1. sydfs文件系统
Sydfs是系统数据运行的 只读文件系统 ;Sydfs可以通过sdk的download工具来下载存放资源文件,并于系统运行时读取;该文件系统能使用的接口图所示:
- 其中ioctl支持的cmd命令有:
FS_IOCTL_FILE_TOTAL:
示例: int file_total; vfs_ioctl(pfile, FS_IOCTL_FILE_TOTAL, (int)&file_total); file_total即为pfile文件所在文件系统的总文件数;FS_IOCTL_FS_TOTAL:
示例: int file_total; vfs_ioctl(pfs, FS_IOCTL_FILE_TOTAL, (int)&file_total); file_total即为pfs文件系统的总文件数;FS_IOCTL_FILE_ATTR:
示例: struct vfs_attr attr; vfs_ioctl(pfile, FS_IOCTL_FILE_ATTR, (int)&attr); attr即可获取pfile文件的位置和大小;
备注
通过ioctl获取的文件位置仅为该pfile文件在其上层目录下的相对偏移; 若要获取该文件相对于flash的偏移地址,需要调用vfs_get_fsize();
2.1.2. norfs文件系统
Norfs是一个循环管理的可读写文件系统;Norfs内部空间环形管理,空间不足时新写入的文件会覆盖之前的文件;norfs文件系统只通过文件号进行管理,创建新文件后文件号会累加;该文件系统一般在录音时使用;该文件系统能使用的接口如图所示:
- 其中ioctl支持的cmd命令有:
FS_IOCTL_FILE_TOTAL,同上
FS_IOCTL_FS_TOTAL,同上
FS_IOCTL_FILE_ATTR,同上
FS_IOCTL_FILE_SYNC:
示例: u32 flen = 0; vfs_ioctl(pfile, FS_IOCTL_FILE_SYNC, (int)&flen); 该命令一般在录音结束时调用,用于更新norfs录音文件头,flen传入时为需要舍弃的录音末尾字节数,调用结束后会flen会被赋值为录音文件的字节数;FS_IOCTL_FILE_INDEX:
示例: int file_index; vfs_ioctl(pfile, FS_IOCTL_FILE_INDEX, (int)&file_index); file_index即为pfile文件所在norfs文件系统的最新文件序号;FS_IOCTL_FS_INDEX:
示例: int file_index; vfs_ioctl(pfs, FS_IOCTL_FS_INDEX, (int)&file_index); file_index即为pfs所指的norfs文件系统的最新文件序号;
2.1.3. fat/simple_fat文件系统
FatFs是一个通用的文件系统;在本机中,FAT不支持对FAT12、exFAT和sector大小大于512byte的FAT文件系统进行写操作,读操作正常;Simple_FAT为FAT裁切版,只能通过路径打开文件和读文件接口;FAT文件系统能使用的接口如下图所示:
- 其中ioctl支持的cmd命令有:
FS_IOCTL_FILE_INDEX:
示例: int file_index; vfs_ioctl(pfile, FS_IOCTL_FILE_INDEX, (int)&file_index); file_index即为pfile文件所在fat文件系统的最新文件序号;
2.2. 文件系统使用一般流程
如图,vfs运行大致流程如下;
小技巧
可以通过调用接口得到的返回值查看是否调用成功,以及失败的原因;
失败原因可在Headers/include_lib/common/errno-base.h中查看。
2.3. 通用文件系统管理函数
通用文件系统管理函数将介绍sydfs、norfs、fatfs通用的接口,各文件系统具体能使用哪些接口请查看上面的几张图片,下一小节将介绍fatfs独有的相关文件系统接口;
2.3.1. 函数void vfs_init(void)
此函数实现对所有文件系统驱动的初始化;在开机第一次调用即可。
2.3.2. 函数u32 vfs_mount(void **ppvfs, void *device, void *type)
此函数实现对指定设备挂在指定类型的文件系统,所挂载的系统必须设备自身支持;其中参数:
1. ppvfs:文件系统句柄指针,若句柄指向为NULL,函数会自行申请空间; 2. device:设备句柄; ① 需要打开sydfs时,若句柄为空,则会使用内置flash; ② 需要打开norfs等其他文件系统时,句柄不能为空; 3. type:文件系统类型的字符串; ① 可选择”sydfile”、”norfs”、”fat”或0,若该值为0,默认使用sydfile; ② 注:norfs文件系统仅为录音到内置FLASH的应用使用!! 4. 返回值: ① 成功 0; ② 失败 错误请查看errno-base.h。示例1
在内置flash挂载syd文件系统 void *device = dev_open(__SFC_NANE, 0);//获取内置flash设备句柄 void *pfs = NULL; u32 err = vfs_mount(&pfs, device, “sydfile”); //内置flash挂载syd文件系统 if (pfs != NULL && err == 0) { //内置flash挂载sydfs成功 }示例2
在外挂flash上挂载norfs文件系统 void *device = dev_open(__EXT_FLASH_NANE, 0);//获取外挂flash设备句柄 void *pfs = NULL; u32 err = vfs_mount(&pfs, device, “norfs”); //外置flash挂载norfs文件系统 if (pfs != NULL && err == 0) { //外置flash挂载norfs成功 }示例3
在SD卡上挂载fat文件系统 void *device = dev_open(__SD0_NANE, 0);//获取sd卡设备句柄 void *pfs = NULL; u32 err = vfs_mount(&pfs, device, “fat”); //sd卡挂载fat文件系统 if (pfs != NULL && err == 0) { //sd卡挂载fat成功 }
2.3.3. 函数u32 vfs_openbypath(void *pvfs, void **ppvfile, const char *path)
此函数实现打开指定路径的文件,norfs文件系统无法使用此功能。其中参数:
1. pvfs:已挂载的文件系统句柄; 2. ppvfile:文件句柄指针,若句柄指向为NULL,函数会自行申请空间; 3. path:路径字符串; ① 如果字符串只是包含文件夹名,那么会打开文件夹,打开的文件夹仅可用于校验CRC16; ② 如果字符串里面包含了完成的文件名,那么会同时包含文件名! ③ 如果字符串为空,则返回错误; 4. 返回值: ① 成功 0; ② 失败 错误请查看errno-base.h。示例:
在挂载(vfs_mount)成功的前提下,打开dir_song里的so001.f1a歌曲 void *pfile = NULL; u32 err = vfs_openbypath(pfs, &pfile, “dir_song/so001.f1a”); if (pfile != NULL && err == 0) { //成功打开dir_song文件夹里的so001.f1a文件 }
2.3.4. 函数u32 vfs_openbyindex(void *pvfs, void **ppvfile, u32 index)
此函数实现打开指定文件号的文件,其中参数:
1. pvfs:已挂载的文件系统句柄; 2. ppvfile:文件句柄指针,若句柄指向为NULL,函数会自行申请空间; 3. index:文件序号; 4. 返回值: ① 成功 0; ② 失败 错误请查看errno-base.h。
2.3.5. 函数u32 vfs_createfile(void *pvfs, void **ppvfile, u32 *pindex)
此函数实现norfs、fatfs创建一个新的文件,syd_fs无法使用此功能。文件创建和操作结束后,需要调用vfs_file_close()关闭文件,其中参数:
1. pvfs:已挂载的文件系统句柄; 2. ppvfile:文件句柄指针,若句柄指向为NULL,函数会自行申请空间; 3. pindex:文件序号; ① norfs:传入的pindex会被赋值为最新的文件序号; 注意:norfs文件创建和操作结束后,需要先调用vfs_ioctl()接口传入FS_IOCTL_FILE_SYNC命令更新文件信息后再关闭文件; ② fatfs:传入文件存放位置,如”/test.txt”即在根目录创建test.txt文件;; 注意:路径有文件夹时文件夹必须存在,否则创建失败。可先调用vfs_mk_dir()创建文件夹;创建文件时支持长文件名,长文件名路径需传入Unicode码进去并开启FOPEN_LONG宏定义和相应的库(详情见demo代码); ③ sydfs:不支持此功能; 4. 返回值: ① 0; ② 失败 错误请查看errno-base.h。示例1:
挂载norfs文件系统成功前提下,创建一个新的文件 void *pfile = NULL; int index; u32 err = vfs_createfile(pfs, &pfile, (u32)&index); if (pfile != NULL && err == 0) { //norfs文件系统下文件创建成功,index会被赋值为所创建文件的序号 }示例2:
挂载fat文件系统成功前提下,创建一个新的文件 void *pfile = NULL; char *path = “/abcd.txt”; u32 err = vfs_createfile(pfs, &pfile, (u32)path); if (pfile != NULL && err == 0) { //fat文件系统下文件abcd.txt创建成功 }
2.3.6. 函数u32 vfs_read(void *pvfile, void *buf, u32 len)
此函数实现对指定文件的读操作。其中参数:
1. pvfile:已打开的文件句柄; 2. buf:数据buff; 3. len:需要读取的字节长度; 4. 返回值: ① 成功 读取的字节数; ② 失败 0。示例:
打开文件成功前提下,读取文件数据 u8 read_buf[32]; u32 read_len = vfs_read(pfile, (void \*)read_buf, 32); if (read_len != 0) { //成功读取pfile中read_len长度的数据到read_buf里 }
2.3.7. 函数u32 vfs_write(void *pvfile, void *buf, u32 len)
此函数实现对指定文件的写操作,syd_fs无法使用此功能,其中参数:
1. pvfile:已打开的文件句柄; 2. buf:数据buf; 3. len:需要写入的字节长度; 4. 返回值: 成功 写入的字节数; 失败 错误请查看errno-base.h。示例:
打开文件成功前提下,往文件写入数据 u8 write_buf[32] = {0, 1, 2, 3 ... 31}; u32 write_len = vfs_write(pfile, (void *)write_buf, 32); if (write_len != 0) { //成功将write_buf中write_len长度的数据写入到pfile }
2.3.8. 函数u32 vfs_seek(void *pvfile, u32 offset, u32 mode)
此函数实现改变指定文件中读写指针的偏移,其中参数:
1. pvfile:已打开的文件句柄; 2. offset:偏移量; 3. mode:seek模式选择。如图4.2,seek模式有3种,分别为: ① SEEK_SET:从文件起始位置开始向后偏移,首先会判断偏移量是否大于文件长度,若小于则使文件读写指针rw_p = offset; ② SEEK_CIR:从文件读写指针位置开始向后偏移,使rw_p = rw_p + offset; ③ SEEK_END:从文件末尾位置向前偏移,首先会判断偏移量是否大于文件长度,若小于则使rw_p = 文件长度 - offset; 4. 返回值:0。下图为seek模式的选择:
2.3.9. 函数u32 vfs_file_close(void **ppvfile)
此函数实现关闭文件并释放句柄,其中参数:
1. ppvfile:已打开的文件句柄指针; 2. 返回值:0。示例:
vfs_file_close(&pfile); if (pfile == NULL) { //成功关闭pfile文件 }
2.3.10. 函数u32 vfs_fs_close(void **ppvfs)
此函数实现关闭文件系统并释放相关句柄,nor_fs无法使用此功能,其中参数:
1. ppvfs:已挂载的文件系统句柄指针; 2. 返回值:NULL。示例:
vfs_fs_close(&pfs); if (pfs == NULL) { //成功关闭pfs文件系统 }
2.3.11. 函数u32 vfs_file_name(void *pvfile, void *name, u32 len)
此函数实现获取指定文件句柄的文件名,其中参数:
1. pvfile:已打开的文件句柄; 2. name:存放文件名的buf; 3. len:获取文件名的长度; 4. 返回值:成功 返回获取文件名的长度;
2.3.12. 函数int vfs_get_attrs(void *pvfile, void *pvfs_attr)
- 此函数实现记录文件的属性,包括文件大小和地址,nor_fs无法使用此功能,其中参数: ::
pvfile:已打开的文件句柄;
pvfs_attr:文件系统属性,需要传入vfs_attr结构体类型的指针;
返回值:0。
示例:
struct vfs_attr file_attr; vfs_get_attrs(pfile, &file_attr); //文件地址和大小分别保存在file_attr.sclust和file_attr.fsize中
2.3.13. 函数int vfs_ioctl(void *pvfile, int cmd, int arg)
此函数实现对指定文件的相关操作,各文件系统具体的cmd命令请查看《文件系统介绍》小节,其中参数:
1. pvfile:已打开的文件句柄; 2. cmd:命令; 3. arg:参数; 4. 返回值: 成功 0; 失败 错误请查看errno-base.h。cmd:命令主要有7种:
vfs_ioctl cmd命令
命令含义
FS_IOCTL_DIR_FILE_TOTAL
获取文件所在文件系统下的文件数。该命令会将arg的值作为地址,并把文件句柄所在文件系统下的所有文件数赋给arg指向的值;若arg参数为0,返回错误E_PAGE_NULL;
FS_IOCTL_FILE_TOTAL
同上;
FS_IOCTL_FS_TOTAL
获取文件系统下的文件数。该命令会将arg的值作为地址,并将特定情况下传入的文件系统句柄下的所有文件数赋值给arg指向的值;若arg参数为0,返回错误E_PAGE_NULL;
FS_IOCTL_FILE_ATTR
获取文件地址参数。该命令会将arg的值作为地址并指向vfs地址参数,并把文件长度以及地址赋值给vfs地址参数;若arg参数为0或文件句柄为NULL,返回错误E_PAGE_NULL或E_PFILE_NULL;
FS_IOCTL_FILE_SYNC
同步文件。该命令会将录音文件同步并将arg的值作为末尾裁切的字节长度;若arg参数为0则不进行裁切;
FS_IOCTL_FILE_INDEX
通过文件指针获取文件索引号。该命令会将arg的值作为地址,并把文件的索引号赋值给arg指向的值。
FS_IOCTL_FS_INDEX
通过文件系统指针获取文件索引号。该命令会将arg的值作为地址,并把文件的索引号赋值给arg指向的值。
2.3.14. 函数int vfs_file_crc(void *pvfile)
此函数实现计算文件的CRC16校验值,目前仅SYD可使用此功能,其中参数:
1. pvfile:已打开的文件句柄; 2. 返回值:CRC校验值,计算错误则返回0; 注意:V1.4.0以及之后的SDK,可以通过openbypath方式打开资源文件进行校验,也可打开dir文件用于校验;打开dir文件方式仅用于校验!示例:
vfs_openbypath(pfs, &pfile, “/dir_song”); //校验打包后的dir文件 u16 crc16 = vfs_file_crc(pfile);示例2:
vfs_openbypath(pfs, &pfile, “/dir_song/so001.f1a”);//校验资源文件 u16 crc16 = vfs_file_crc(pfile);
2.4. FAT文件系统管理函数
下面的函数为仅FAT使用的接口,在app\bsp\common\fs\fat\fat_resource.c中的fat_demo()接口,可以找到下列函数的使用示例;
2.4.1. 函数int vfs_ftell(void *pvfile, void *parm)
此函数实现获取文件读写指针,仅FAT可使用该功能。其中参数:
1. pvfile:已打开的文件句柄; 2. param:用于保存文件系统读写指针; 3. 返回值: 成功 0; 失败 错误请查看errno-base.h。
2.4.2. 函数int vfs_get_fsize(void *pvfile, void *parm)
此函数实现获取文件大小,仅FAT可使用该功能。其中参数:
1. pvfile:已打开的文件句柄; 2. param:用于保存文件大小的指针; 3. 返回值: 成功 0; 失败 错误请查看errno-base.h。
2.4.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。
小技巧
扫描文件后缀名若超过3个字符,则只识别前面3个字符
后缀名若少于3个字符,则不足部分用?代替,如(A格式:A??)
2.4.4. 函数void vfs_fscan_release(void *pvfs, struct vfscan *fs)
此函数实现释放文件扫描句柄,仅FAT可使用该功能,与vfs_fscan()搭配调用。其中参数:
1、pvfs:已挂载的文件系统句柄; 2、fs:文件扫描句柄; 3、返回值:无。
2.4.5. 函数int vfs_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。
2.4.6. 函数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。
2.4.7. 函数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。
2.4.8. 函数u32 vfs_file_delete(void *pvfile)
此函数实现文件的删除,仅FAT可使用该功能。其中参数:
1、pvfile:已打开的文件句柄; 2、返回值: 成功 0; 失败 错误请查看errno-base.h。
2.4.9. 函数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。