网站开发的ie兼容做到9,东山县城乡规划建设局网站,福永做网站,南通市规划建设局网站本专栏争取每周三更新直到更新完成#xff0c;期待大家的订阅关注#xff0c;欢迎互相学习交流。 本文需要一些SD卡和内存管理等前置知识#xff0c;后续文章会介绍#xff0c;这里先介绍一下FATFS文件系统。关于FATFS的文章分为上下两篇#xff0c;上篇主要介绍什么是FAT… 本专栏争取每周三更新直到更新完成期待大家的订阅关注欢迎互相学习交流。 本文需要一些SD卡和内存管理等前置知识后续文章会介绍这里先介绍一下FATFS文件系统。关于FATFS的文章分为上下两篇上篇主要介绍什么是FAT文件系统以及FATFS的移植下篇主要介绍FATFS的一些API函数并给出一些简单的应用示例。 目录 一、结构体介绍1.1 文件对象结构体1.2 目录对象结构体1.3 文件信息结构体 二、文件操作函数2.1 f_open函数2.2 f_close函数2.3 f_read函数2.4 f_write函数2.5 f_size获取文件大小 三、目录操作函数3.1 f_opendir函数3.2 f_closedir函数3.3 f_readdir函数 四、文件/目录管理函数4.1 f_unlink函数4.2 f_rename函数4.3 f_mkdir函数 五、示例程序5.1 文件操作函数使用示例5.2 目录操作函数使用示例 一、结构体介绍 在开始正式介绍FATFS的API函数之前我们先来看几个关键的结构体主要是简单了解一下其中的内容。
1.1 文件对象结构体
/* File object structure (FIL) */typedef struct {FATFS* fs; /* Pointer to the related file system object (**do not change order**) */WORD id; /* Owner file system mount ID (**do not change order**) */BYTE flag; /* Status flags */BYTE err; /* Abort flag (error code) */DWORD fptr; /* File read/write pointer (Zeroed on file open) */DWORD fsize; /* File size */DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLYDWORD dir_sect; /* Sector number containing the directory entry */BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
#if _USE_FASTSEEKDWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
#endif
#if _FS_LOCKUINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
#if !_FS_TINYBYTE buf[_MAX_SS]; /* File private data read/write window */
#endif
} FIL;1.2 目录对象结构体
/* Directory object structure (DIR) */typedef struct {FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */WORD id; /* Owner file system mount ID (**do not change order**) */WORD index; /* Current read/write index number */DWORD sclust; /* Table start cluster (0:Root dir) */DWORD clust; /* Current cluster */DWORD sect; /* Current sector */BYTE* dir; /* Pointer to the current SFN entry in the win[] */BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _FS_LOCKUINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if _USE_LFNWCHAR* lfn; /* Pointer to the LFN working buffer */WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
#if _USE_FINDconst TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} DIR;1.3 文件信息结构体
/* File information structure (FILINFO) */typedef struct {DWORD fsize; /* File size */WORD fdate; /* Last modified date */WORD ftime; /* Last modified time */BYTE fattrib; /* Attribute */TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFNTCHAR* lfname; /* Pointer to the LFN buffer */UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;二、文件操作函数
2.1 f_open函数
函数功能打开或者创建一个文件。函数原型FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode);输入参数*fp指向一个空白文件对象的结构体指针 *path文件名指针 mode模式标志共有以下几种模式
模式含义FA_READ指定对对象的读访问权限。可以从文件中读取数据。FA_WRITE指定对对象的写访问。数据可以写入文件。结合 FA _ READ 进行读写访问。FA_OPEN_EXISTING打开文件。如果文件不存在函数将失败 (默认值)。FA_OPEN_ALWAYS如果文件存在则打开该文件如果没有将创建一个新文件。FA_CREATE_NEW创建一个新文件。如果文件存在函数将失败。FA_CREATE_ALWAYS创建一个新文件。如果该文件存在它将被截断并覆盖。 当 _ FS _ READONLY 1时只读模式模式标志 FA _ WRITE、 FA _ CREATE _ ALWAYS、 FA _ CREATE _ NEW 和 FA _ OPEN _ ALWAYS 不可用。 返回值返回值是一个结构体这里在每一个返回值后面给出了中文描述仅供参考。
typedef enum {FR_OK 0, /* (0) 成功*/FR_DISK_ERR, /* (1) 低级磁盘 I/O 层发生了一个硬错误 */FR_INT_ERR, /* (2) 断言失败 */FR_NOT_READY, /* (3) 物理驱动无法工作 */FR_NO_FILE, /* (4) 无法找到文件 */FR_NO_PATH, /* (5) 无法找到路径 */FR_INVALID_NAME, /* (6) 路径名格式无效 */FR_DENIED, /* (7) 由于禁止访问或目录已满而拒绝访问 */FR_EXIST, /* (8) 由于禁止访问而拒绝访问 */FR_INVALID_OBJECT, /* (9) 文件/目录对象无效 */FR_WRITE_PROTECTED, /* (10) 物理驱动器受写保护 */FR_INVALID_DRIVE, /* (11) 逻辑驱动器号无效 */FR_NOT_ENABLED, /* (12) 卷没有工作区 */FR_NO_FILESYSTEM, /* (13) 没有有效的FAT卷 */FR_MKFS_ABORTED, /* (14) 由于任何参数错误f _ mkfs ()中止 */FR_TIMEOUT, /* (15) 无法获得在规定期限内访问卷的授权 */FR_LOCKED, /* (16) 根据文件共享策略拒绝该操作 */FR_NOT_ENOUGH_CORE, /* (17) 无法分配 LFN工作缓冲区 */FR_TOO_MANY_OPEN_FILES, /* (18) 打开的文件数 gt; _ FS _ SHARE */FR_INVALID_PARAMETER /* (19) 给定的参数无效 */
} FRESULT;注意事项在使用任何文件函数之前必须使用 f _ mount 函数将工作区(文件系统对象)注册到逻辑驱动器f_mount 函数后续会介绍。除 f _ fdisk 函数之外的所有 API 函数都可以在此过程之后工作。打开的文件必须在断电、删除媒体或重新挂载之前关闭否则文件可能会被折叠。若要关闭打开的文件请使用 f _ close 函数。禁止复制打开任何写模式标志的文件。。
2.2 f_close函数
函数功能关闭一个打开的文件。函数原型FRESULT f_close (FIL* fp);输入参数*fp指向要关闭的打开文件对象结构的指针。返回值包含在FRESULT结构体不再详细介绍。注意事项如果任何数据已经写入文件文件的缓存信息将被写回卷。函数成功执行后file 对象不再有效可以将其丢弃。
2.3 f_read函数
函数功能从一个文件中读取数据。函数原型FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br);输入参数*fp指向打开文件对象的指针 *buff指向存储读取数据的数组指针 btr在 UINT 类型范围内要读取的字节数 *br指向 UINT 变量的指针以返回读取的字节数。无论结果如何该值在函数调用后始终有效返回值包含在FRESULT结构体不再详细介绍。注意事项文件对象的文件读/写指针提高了读取的字节数。函数完成后应该检查 * br 以检测文件的结尾。如果 * br 小于 btr则表示在读操作期间读/写指针到达文件末尾。
2.4 f_write函数
函数功能往文件里写入数据。函数原型FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw);输入参数*fp指向打开文件对象的指针 *buff指向要写入的数据的指针 btw指定要在 UINT 类型范围内写入的字节数 *bw指向 UINT 变量的指针以返回写入的字节数返回值包含在FRESULT结构体不再详细介绍。注意事项函数完成后应该检查 * bw 以检测磁盘是否已满。如果 * bw 小于 btw则表示在写操作期间卷已满。该函数可以在卷满或接近满时执行。 经测试发现写完成后必须关闭文件才能保存写的数据如果写完成后不关闭文件直接读取新写入的内容不会被读取出来。 2.5 f_size获取文件大小 f_size 函数获取文件的大小返回文件的大小以字节为单位。它是作为宏实现的只需要输入一个指向打开的文件对象结构的指针即可使用比较简单这里之所以单独介绍这个函数是因为我们后续在使用SD卡读取文件时很多时候需要先知道文件大小然后开辟合适的空间来存储读取出来的文件内容。f_size函数的定义如下
#define f_size(fp) ((fp)-fsize)三、目录操作函数
3.1 f_opendir函数
函数功能打开一个目录文件夹。函数原型FRESULT f_opendir (DIR* dp, const TCHAR* path);输入参数*dp指向空白目录对象的指针以创建新的目录对象 *path指向指定要打开的目录名称的空终止字符串的指针返回值包含在FRESULT结构体不再详细介绍。注意事项当_FS_MINIMIZE 1时可用。 f_opendir函数是打开一个已存在的目录并为后续的调用创建一个目录对象。该目录对象结构可以在任何时候不经任何步骤而被丢弃。 3.2 f_closedir函数
函数功能关闭一个打开的目录。函数原型FRESULT f_closedir (DIR* dp);输入参数指向要关闭的已打开目录对象结构的指针。返回值包含在FRESULT结构体不再详细介绍。
3.3 f_readdir函数
函数功能读取目录条目。函数原型FRESULT f_readdir (DIR* dp, FILINFO* fno);输入参数*dp指向由 f _ opendir 函数创建的目录对象的指针 *fno指向文件信息结构的指针以存储有关已读项的信息返回值包含在FRESULT结构体不再详细介绍。注意事项f_readdir函数按顺序读取目录项、关于文件和目录的信息。通过重复调用 f _ readdir 函数可以读取目录中的所有项。 当启用相对路径特性(_ FS _ RPATH 1)时点条目不会被过滤掉它们将出现在读取条目中。当所有目录项都已读取且没有要读取的项时空字符串存储在 fno- fname []中不会出现任何错误。当指向 fno 的空指针被赋值时目录对象的读索引将被重绕。 启用 LFN 特性长文件名后文件信息结构中的 fno- lfname 和 fno- lfsize 在使用之前必须使用有效值进行初始化。lfname 指向 LFN 读取缓冲区。lfsize 是以 TCHAR 为单位的 LFN 读缓冲区的大小。如果不需要 LFN则将 lfname设置为一个空指针则不返回 LFN。 这里简单介绍几句相对路径和绝对路径至于更加详细的内容还需要大家自行搜索。其实很好理解绝对路径是指文件在硬盘上真正存在的路径绝对路径是唯一的只有一个而相对路径是相对于当前目录或者当前工作目录的路径表示文件相对于当前位置的路径。我们常见的带盘符的路径都是绝对路径比如C:\Users\de’l’l\Desktop\doc这种而相对路径是相对一个目标对象而言的它有自己的表示方式“.”表示当前所在目录“…”代表上一层目录“…\”代表上一层目录的上一层目录。 对于f_readdir函数给出了示例程序这里贴一下后续会使用该函数来打印一下某个特定文件夹下的文件
FRESULT scan_files (char* path /* Start node to be scanned (also used as work area) */
)
{FRESULT res;FILINFO fno;DIR dir;int i;char *fn; /* This function assumes non-Unicode configuration */
#if _USE_LFNstatic char lfn[_MAX_LFN 1]; /* Buffer to store the LFN */fno.lfname lfn;fno.lfsize sizeof lfn;
#endifres f_opendir(dir, path); /* Open the directory */if (res FR_OK) {i strlen(path);for (;;) {res f_readdir(dir, fno); /* Read a directory item */if (res ! FR_OK || fno.fname[0] 0) break; /* Break on error or end of dir */if (fno.fname[0] .) continue; /* Ignore dot entry */
#if _USE_LFNfn *fno.lfname ? fno.lfname : fno.fname;
#elsefn fno.fname;
#endifif (fno.fattrib AM_DIR) { /* It is a directory */sprintf(path[i], /%s, fn);res scan_files(path);path[i] 0;if (res ! FR_OK) break;} else { /* It is a file. */printf(%s/%s\n, path, fn);}}f_closedir(dir);}return res;
}四、文件/目录管理函数 下面介绍的这几个文件/目录管理函数的使用都比较简单下面就不再单独给出应用示例了。
4.1 f_unlink函数
函数功能删除一个文件或子目录。函数原型FRESULT f_unlink (const TCHAR* path);输入参数*path文件/文件夹路径。返回值包含在FRESULT结构体不再详细介绍。注意事项如果要删除的对象的条件适用于以下条件则无法使用本函数删除 文件/子目录不能有只读属性(AM _ RDO) 否则函数将被 FR _ DENIED 拒绝。 子目录必须为空并且不能被工作目录否则函数将被拒绝。 当启用文件锁定功能时它将被安全地拒绝。
4.2 f_rename函数
函数功能重命名文件或子目录。函数原型FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new);输入参数*path_old旧对象名称 *path_new新对象名称返回值包含在FRESULT结构体不再详细介绍。注意事项要重命名的对象不能是打开的对象。当启用文件锁定功能时可以安全地拒绝这种错误操作。
4.3 f_mkdir函数
函数功能创建一个新目录。函数原型FRESULT f_mkdir (const TCHAR* path);输入参数*path目录名。返回值包含在FRESULT结构体不再详细介绍。
五、示例程序
5.1 文件操作函数使用示例 为了方便大家更好地理解FATFS的API函数的使用方法我们这里通过一个小例子来演示一下本例需要用到以下内容
一张格式化过的空的SD卡一个可以插SD卡的开发板或模块这里使用的是STM32F103ZET6核心板一块LCD显示屏屏幕主要是为了显示提示信息可有可无可以用串口来代替 本例主要目的是在一张空的SD卡中创建并打开一个新的.txt文件向文件中写入“ABCDEFGH”然后读取文件内容并显示最后读取一下文件大小。 这里贴一下核心代码代码中有个别打开文件和关闭文件的操作没有进行返回值检测不影响实际测试这里特地说明一下。 f_mount(fs[0],0:,1); //挂载SD卡// 打开一个文件如果文件不存在则创建一个res f_open(fil, ERTUElec.txt,FA_OPEN_ALWAYS | FA_WRITE);// 判断是否创建成功if (!res){LCD_ShowString(30,80,200,16,16,File Creat Success!);}else{LCD_ShowString(30,80,200,16,16,File Creat faild! );}// 写入数据res f_write(fil,writeData[0],8,(UINT*)bw);// 判断是否写入成功if (!res){LCD_ShowString(30,100,200,16,16,File Write Success!);f_close(fil);}else{LCD_ShowString(30,100,200,16,16,File Write faild! );}f_open(fil, ERTUElec.txt,FA_READ);// 读取文件res f_read(fil,readData[0],8,(UINT*)br);// 判断是否读取成功if (!res){LCD_ShowString(30,120,200,16,16,File Read Success!);}else{LCD_ShowString(30,120,200,16,16,File Read faild! );}// 关闭打开的文件res f_close(fil);// 判断是否关闭成功if (!res){LCD_ShowString(30,140,200,16,16,File Close Success!);}else{LCD_ShowString(30,140,200,16,16,File Close faild! );}// 显示读取内容sprintf ((char*)string,Content is %s,readData);LCD_ShowString(30,160,200,16,16,string);// 获取文件大小字节数size f_size(fil);// 显示文件大小sprintf ((char*)string,Size is %d,size);LCD_ShowString(30,180,200,16,16,string); 下面看一下LCD上显示的信息 5.2 目录操作函数使用示例 本示例比较简单就是使用f_readdir函数来读取一个特定文件加下的全部文件名并通过串口打印。首先我们在SD卡中新建一个文件夹文件夹内添加一些文件用来测试 然后我们利用介绍f_readdir函数时给出的示例函数将NEW文件夹内的全部文件名通过串口打印出来示例函数在上面已经给出了这里就不再重复介绍了在使用时只需要输入文件夹路径即可 scan_files(0:/NEW);上电后观察串口输出内容