FATFS学习笔记

FATFS学习笔记 声明这个笔记是基于B站“李述铜聊嵌入式”老师的《FATFS文件系统详解系列之一5小时快速入门嵌入式文件系统FATFS》课程的个人学习笔记。一1.1 什么是文件系统1.为什么需要文件系统对于一些较小的简单的数据可以直接储存在MCU内部的Flash里或者外挂一颗小的EEPROMEEPROM 可以理解为一个容量很小但很“耐用”的存储器非常适合用来保存那些需要频繁修改、断电后也不能丢失的少量数据。如果数据量再大一些可以外挂一颗大容量的SPI接口的Flash。2.文件系统到底是什么1.2 FAT文件系统简介1.起源2.储存设备一般结构3.FAT文件系统结构directory entry它就像文件系统里的“通讯录”用于记录文件名、文件大小、在存储设备上的位置、创建修改时间等信息作用是帮助操作系统快速找到文件。像FATFS这类嵌入式文件系统就是通过它来管理文件和目录的。1.3 什么是FATFSRTOSRTOS 的全称是Real-Time Operating System中文叫实时操作系统。可以把它理解成一个能同时处理多件事的“超级循环调度员”。平时写的while(1)大循环裸机编程就像一个人在做多件事先看一眼按键有没有按下再去处理串口数据再去刷新屏幕再回去看按键……他是一件一件轮流做的如果某件事卡住了比如等待网络响应后面的事也会被耽误。而 RTOS 就像给每件事分配一个独立的小工人工人 A 专门负责按键工人 B 专门负责串口工人 C 专门负责语音播报这些工人可以同时工作看起来而且重要的事可以优先处理比如紧急停止按钮按下立刻打断其他任务。RTOS 是一个让单片机能够“同时”执行多个任务的“操作系统内核”。它帮你管理任务的切换、优先级和通信。二2.1 挂载文件系统作用FASFS使用前需进行挂载操作才能对相应的文件和目录进行访问。#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res_1 ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res_2 ! FR_OK) { printf(mount disk2 failed.\n); return -1; } f_unmount(0:); //卸载磁盘0参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }2.2 打开与关闭文件系统文件打开文件关闭#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/b.txt, FA_READ); //打开磁盘0根目录下的b.txt文件FA_READ表示以只读方式打开文件,把文件的相关信息保存在file对象中 if (res ! FR_OK) { printf(open file error.\n); return -1; } f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/b.txt, FA_OPEN_APPEND | FA_WRITE); //打开磁盘0根目录下的b.txt文件参数分别是文件对象、路径和模式FA_OPEN_APPEND表示以追加模式打开文件如果文件不存在则创建,FA_WRITE表示以写入模式打开文件 if (res ! FR_OK) { printf(open file error.\n); return -1; } f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }2.3 读取和写入文件读取文件写入文件#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/rtos/os_sem.c, FA_READ); //打开磁盘0根目录下的rtos目录中的os_sem.c文件FA_READ表示以只读方式打开文件 if (res ! FR_OK) { printf(open file error.\n); return -1; } while (1) { static char read_buf[1024]; //定义一个字符数组read_buf用于存储从文件中读取的数据 UINT read_size; //定义一个UINT类型的变量read_size用于存储实际读取的字节数 res f_read(file, read_buf, sizeof(read_buf) - 1, read_size); //从文件对象file中读取数据到read_buf中读取的最大字节数为sizeof(read_buf) - 1实际读取的字节数存储在read_size中 if (res ! FR_OK) { printf(\n read error.\n); break; } //read_buf的最后一项改成\0, //read_size 是已读取的字节数它指向缓冲区中第一个未占用的位置。所以 read_buf[read_size] 就是紧跟在有效数据后面的位置正好用来放 \0。不需要 1因为 read_size 已经正确表示了结束符的索引。 read_buf[read_size] \0; printf(%s,read_buf); //判断是否读完读完跳出程序 if (read_size sizeof(read_buf) - 1) { printf(\n---read comp---/n); break; } } f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }文件写入刷新#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/sync.txt, FA_WRITE | FA_CREATE_ALWAYS); //打开磁盘0根目录下的sync.txt文件使用写入模式如果文件不存在则创建如果存在则覆盖 if (res ! FR_OK) { printf(open file error.\n); return -1; } for (int i 0; i 10000; i) { static char write_buf[100]; //定义一个静态字符数组writr_buf用于存储要写入文件的数据 int len sprintf(write_buf, %d:%s\n, i, 12345678); //使用sprintf函数将格式化的字符串写入write_buf中格式为i:12345678\n其中i是循环变量的值len是写入字符串的长度 UINT write_size; //实际写入的长度 res f_write(file, write_buf, len, write_size); //调用f_write函数将write_buf中的数据写入文件参数分别是文件对象、数据缓冲区、要写入的字节数和实际写入的字节数 if (res ! FR_OK) //判断写入是否成功如果返回值不是FR_OK则输出错误信息并跳出循环 { printf(write file error.\n); break; } if (i 5000) { f_sync(file); //调用f_sync函数将文件对象file的缓冲区数据强制写入磁盘确保数据的持久化 *(unsigned char*)0 0x1234; //故意触发一个访问违规的错误模拟程序崩溃的情况 } } f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }文件写入示例代码#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/sync.txt, FA_WRITE | FA_CREATE_ALWAYS); //打开磁盘0根目录下的sync.txt文件使用写入模式如果文件不存在则创建如果存在则覆盖 if (res ! FR_OK) { printf(open file error.\n); return -1; } for (int i 0; i 10000; i) { static char write_buf[100]; //定义一个静态字符数组writr_buf用于存储要写入文件的数据 int len sprintf(write_buf, %d:%s\n, i, 12345678); //使用sprintf函数将格式化的字符串写入write_buf中格式为i:12345678\n其中i是循环变量的值len是写入字符串的长度 UINT write_size; //实际写入的长度 res f_write(file, write_buf, len, write_size); //调用f_write函数将write_buf中的数据写入文件参数分别是文件对象、数据缓冲区、要写入的字节数和实际写入的字节数 if (res ! FR_OK) //判断写入是否成功如果返回值不是FR_OK则输出错误信息并跳出循环 { printf(write file error.\n); break; } } f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }2.4 以字符串方式读文件#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/rtos/os_sem.c, FA_READ); //打开磁盘0上的文件rtos/os_sem.c以只读模式打开参数分别是文件对象、文件路径和打开模式 if (res ! FR_OK) { printf(open file error.\n); return -1; } while (1) { static TCHAR read_buf[100]; //定义一个静态字符数组read_buf用于存储从文件中读取的数据大小为100字节 TCHAR *str f_gets(read_buf, 100, file); //从文件对象file中读取一行文本数据存储到read_buf中参数分别是读取缓冲区、缓冲区大小和文件对象 if (str NULL) //如果读取失败或到达文件末尾f_gets函数会返回NULL此时跳出循环 { break; } printf(%s, str); //输出读取到的文本数据 } f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }2.5 以字符串方式写文件#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/rtos/os_sem.c, FA_WRITE | FA_OPEN_APPEND); //打开磁盘0目录下的os_sem.c文件参数分别是文件对象、文件路径和打开模式FA_WRITE表示以写入模式打开文件FA_OPEN_APPEND表示如果文件存在则在末尾追加内容 if (res ! FR_OK) { printf(open file error.\n); return -1; } f_puts(rtos is running\n, file); //向文件中写入字符串rtos is running参数分别是要写入的字符串和文件对象 f_putc(o, file); //向文件中写入一个字符o参数分别是要写入的字符和文件对象 f_putc(k, file); f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }2.6 文件读写定位#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/data.bin, FA_READ); //打开磁盘0目录下的data.bin文件参数分别是文件对象、文件路径和打开模式FA_READ表示以只读模式打开文件 if (res ! FR_OK) { printf(open file error.\n); return -1; } static char read_buf[100]; //定义一个静态字符数组read_buf大小为100字节用于存储从文件中读取的数据 UINT read_size; //定义一个UINT类型的变量read_size用于存储实际读取的字节数 //从第32个字节开始读取100个字节的数据到read_buf中参数分别是文件对象、读取缓冲区、要读取的字节数和实际读取的字节数 f_lseek(file, 32); //将文件指针移动到第32个字节的位置准备从该位置开始读取数据 f_read(file, read_buf, sizeof(read_buf), read_size); //从文件中读取数据到read_buf中实际读取的字节数存储在read_size变量中 f_lseek(file, 100); f_read(file, read_buf, sizeof(read_buf), read_size); f_rewind(file); //将文件指针重新定位到文件的开头位置准备从文件的开始位置进行读取或写入操作 f_read(file, read_buf, sizeof(read_buf), read_size); f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }2.7 调整写位置进行扩容#include stdio.h #include ../fatfs/source/ff.h //用路径的方式包含ff.h头文件 static FATFS disk1_fs; //定义一个FATFS类型的变量作为磁盘0的文件系统对象 static FATFS disk2_fs; int main(void) { //挂载磁盘1参数分别是文件系统对象、路径和选项,1为立即挂载文件系统 // fmount在此处的作用是将磁盘0与文件系统对象disk1_fs关联起来使得后续对磁盘0的文件操作能够通过disk1_fs来进行管理和访问 // 0: - disk1.vhd //FRESULT类型的变量res用于接收f_mount函数的返回值判断挂载是否成功 FRESULT res f_mount(disk1_fs, 0:, 1); if (res ! FR_OK) { printf(mount disk1 failed.\n); return -1; //如果挂载失败输出错误信息并返回-1结束程序 } res f_mount(disk2_fs, 1:, 1); if (res ! FR_OK) { printf(mount disk2 failed.\n); return -1; } //在FatFs文件系统中声明一个文件对象file用于后续的文件操作如打开、读取、写入等。 // FIL是FatFs库中定义的一个结构体类型包含了文件的相关信息和状态。 //直接放在函数中占用字节较大放在全局区占用字节较小或用static修饰放在函数中占用字节较小 FIL file; res f_open(file, 0:/data1.bin, FA_WRITE | FA_CREATE_ALWAYS); //打开磁盘0目录下的data1.bin文件参数分别是文件对象、文件路径和打开模式FA_WRITE表示以写入模式打开文件FA_CREATE_ALWAYS表示如果文件已存在则覆盖它如果不存在则创建一个新文件 if (res ! FR_OK) { printf(open file error.\n); return -1; } #if 0 static char read_buf[100]; //定义一个静态字符数组read_buf大小为100字节用于存储从文件中读取的数据 UINT read_size; //定义一个UINT类型的变量read_size用于存储实际读取的字节数 //从第32个字节开始读取100个字节的数据到read_buf中参数分别是文件对象、读取缓冲区、要读取的字节数和实际读取的字节数 f_lseek(file, 32); //将文件指针移动到第32个字节的位置准备从该位置开始读取数据 f_read(file, read_buf, sizeof(read_buf), read_size); //从文件中读取数据到read_buf中实际读取的字节数存储在read_size变量中 f_lseek(file, 100); f_read(file, read_buf, sizeof(read_buf), read_size); f_rewind(file); //将文件指针重新定位到文件的开头位置准备从文件的开始位置进行读取或写入操作 f_read(file, read_buf, sizeof(read_buf), read_size); #endif f_lseek(file, 200); //将文件指针移动到第200个字节的位置准备从该位置开始进行写入操作 f_close(file); //关闭文件对象file释放相关资源 f_unmount(0:); //卸载磁盘1参数是路径0:表示磁盘0 f_unmount(1:); printf(hello, world\n); return 0; }