fatfs源码阅读

摘要:
使用fatfs文件的第一步是调用F_ mount函数注册的工作空间=512WORDsize;/*扇区大小与SD卡中的块相对应,通常为512B*/#endif#if_FS_REENTRANT_SYNC_tsobj;/*标识符同步对象*/#endif#if!f_ mount函数很简单,如下所示:FRESULTf_mount{FATFS*rfs;if/*Checkifhedrivenumbers is valid*/returnFR_INVALID_DRIVE;rfs=FATFS[vol];/*Getcurrentfsobject*/if{rfs-˃fs_type=0;/*Clearoldfsobject*/}if{fs-˃fs_type=0;/*Clearnewfsobject*/}FATFS[vol]=fs;/*注册wfsobject*/returnFR_ OK;}我删除了一些无用的条件编译,发现最后的代码就是上面的代码。事实上它是将FatFs文件系统中定义的FatFs[vol]指针数组的0指向我们传入的工作区---------------------------------------------------------------------------------这是文件对象的属性:typedefstruct{FATFS*fs;/*指向其自己的文件系统*/WORDID;/*OwnerfilesystemmountID*/BYTEflag;/*文件状态ID*/BYTE pad1;DWORDfptr;/*读取/写入指针*/DWORDfsize;/*大小*/DWORDsclust;/*文档开始扇区*/DWORDcluster;/*current扇区*/DWORDdsect;/*当前数据扇区*/#if!

使用fatfs文件的第一步,就是调用F_mount函数注册一个工作空间

 

F_mount函数的原型如下:

fatfs源码阅读第1张

 

 

第一个参数根据网上大神的答复,是外设类型,如果是sd卡就是0flash等等其他的外设就是其他得数,据说有定义,不过我没找到。

第二个参数FATFS指针就是工作空间的指针,个人感觉有点lwip网卡数据结构的感觉。

 

 

FATFS数据结构及解释如下,个人感觉了解FATFS这个工作空间数据结构是什么东西就行:

typedef struct {

    BYTE    fs_type;      /* FAT sub-type (0:Not mounted) */

    BYTE    drv;          /* Physical drive number */

    BYTE    csize;        /*每簇里有多少个扇区 (一般一簇是4KB 一扇区是512B*/

    BYTE    n_fats;       /* FAT表的数目  一般是两个 */

    BYTE    wflag;        /* win[ ] dirty flag */

    BYTE    fsi_flag;     /* fsinfo 区域脏数据标志 */

    WORD    id;           /* File system mount ID */

    WORD    n_rootdir;    /* Number of root directory entries (FAT12/16) */#if _MAX_SS != 512

    WORD    ssize;        /* 扇区大小  对应着sd卡中的block  一般是512B*/

#endif

#if _FS_REENTRANT

    _SYNC_t sobj;         /* Identifier of sync object */#endif

#if !_FS_READONLY

    DWORD   last_clust;   /* Last allocated cluster */

    DWORD   free_clust;   /* 空闲簇的数目*/

    DWORD   fsi_sector;   /* fsinfo sector (FAT32) */

#endif#if _FS_RPATH

    DWORD   cdir;         /* Current directory cluster (0:root) */#endif

    DWORD   n_fatent;     /* Number of FAT entries (== Number of clusters + 2) */

    DWORD   fsize;        /*FAT表对应着多少个扇区*/

    DWORD   fatbase;      /*FAT表的起始扇区 */

    DWORD   dirbase;      /* 根目录的起始扇区*/

    DWORD   database;     /* 数据区的起始扇区 */

    DWORD   winsect;      /* Current sector appearing in the win[ ] */

    BYTE    win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data on tiny cfg) */

} FATFS;

 

 

注册的FATFS并不在f_mount函数中完成对其属性的初始化,而是第一次调用f_open发现还没有初始化的时候在完成初始化。f_mount函数中做得事情很简单,如下:

 

 

 

FRESULT f_mount (

BYTE vol,/* Logical drive number to be mounted/unmounted */

FATFS *fs/* Pointer to new file system object (NULL for unmount)*/

)

{

FATFS *rfs;

 

 

if (vol >= _VOLUMES)/* Check if the drive number is valid */

return FR_INVALID_DRIVE;

rfs = FatFs[vol];/* Get current fs object */

 

if (rfs) {

rfs->fs_type = 0;/* Clear old fs object */

}

 

if (fs) {

fs->fs_type = 0;/* Clear new fs object */

}

FatFs[vol] = fs;/* Register new fs object */

 

return FR_OK;

}

 

 

我删去了一些没用的条件编译,发现最后的代码是上面的代码,其实就是将fatfs文件系统已经定义好的FatFs[vol]指针数组的0号指向我们传进来的工作空间。

 ------------------------------------------------------------------------------------------------------------

这就是一个文件对象的属性:

typedef struct {

    FATFS*  fs;           /* 指向属于自己的文件系统 */

    WORD    id;           /* Owner file system mount ID */

    BYTE    flag;         /*文件状态标识*/

    BYTE    pad1;

    DWORD   fptr;         /* 文件读写指针 (Byte offset origin from top of the file) */

    DWORD   fsize;        /*文件大小*/

    DWORD   sclust;       /*文档开始扇区 */

    DWORD   clust;        /* 当前扇区 */

    DWORD   dsect;        /* Current data sector */

#if !_FS_READONLY

    DWORD   dir_sect;     /* Sector containing the directory entry */

    BYTE*   dir_ptr;      /* Ponter to the directory entry in the window */

#endif

#if !_FS_TINY

    BYTE    buf[_MAX_SS]; /* Data read/write buffer */

#endif

} FIL;

 

上面的是一个文件对象的属性,f_open函数就是用来填充它,而f_close函数则是主要用来将其fs属性置为空,以此让此文件对象失效。

 

F_open

打开一个文件时,有五个选项:

       FA_READ:以读方式打开文件

       FA_WRITE:以写方式打开文件,和上一个组合就变成了以读写的方式打开文件

       FA_OPEN_EXISTING:打开的文件必须已经存在,如不存在函数失败

       FA_OPEN_ALWAYS:如果不存在这个文件,则新建,如果存在这个文件,则在后面添加。用这种方法打开文件要之后调用 f_lseek方法。

       FA_CREATE_NEW:创建一个新文件,如果已经存在,则函数失败。

       FA_CREATE_ALWAYS:创建一个新文件,如果文件存在,则覆盖。

 

 

f_open函数中,调用了下面这个函数:

fatfs源码阅读第2张

 

这个函数会进行检查,如果文件系统对象还不是有效的还不是有效的,则会初始化它。

 

F_close

     用来将文件对象的fs属性置为空,以此让此文件对象失效。其中调用f_sync函数,来将缓冲区的数据写入sd卡。

 

 

 ----------------------------------------------------------------------------------------------------------

比较正常的两个函数F_READF_WRITE

 

F_READ

fatfs源码阅读第3张

 

第一个参数:文件对象

第二个参数:读取所用的的缓冲区

第三个参数:想要读多少字节的数据

第四个参数:这个参数实际的功能是作为一个返回值,告诉使用者函数完成后实际上读了多少数值,那么如果函数完成后*byteread<bytetoread,那就说明这个文件本身没有bytetoread那么大。

 

F_WRITE

fatfs源码阅读第4张

 

这个函数只有在_FS_READONLY == 0时才可以用。

第一个参数:文件对象

第二个参数:针对写入所用的的缓冲区

第三个参数:想要写入少字节的数据

第四个参数:这个参数也是函数的一个返回值,当函数成功执行之后,如果第四个指针所指向的值小于第三个传进去的参数,那就说明,磁盘满了。

 

详细步骤如下:

准备开始写,先查看一下当前的文件的字节数是不是512的整数倍,如果是的话再查看flag标志中,通过查看可以得出缓冲区是不是又一个完整扇区的数据,如果有的话先将缓冲区中一个扇区的数据写入sd卡,写入512*最大整数倍的数据。剩下的存入缓冲区中。

准备开始写,先查看一下当前的文件的字节数是不是512的整数倍,如果不是,说明缓冲区中还有部分数据,那么就用要写入的数据中的一部分填满缓冲区,更新flag标志,然后回到上一段文字。

 

所谓的缓冲区就是文件对象的buf[]属性。

 --------------------------------------------------------------------------------------------------------------

    f_readf_write函数都只能从文件开头开始读写,那么这个时候就需要一个函数来移动当前指针,配合f_readf_write函数,这个函数就是f_lseek

函数原型如下:

fatfs源码阅读第5张

 

第一个参数:文件对象的指针

第二个参数:从文件开始处向后移动多少

 

Offset是指相对于文件起始处的字节数。

在写模式写了一个超过文件大小的offset,文件将被拓展,并且拓展区域的数据是未定义的。这可以用来迅速的创建一个大文件。

F_lseek函数成功后,为确保指针已经以已经成功移动,必须检查文件对象中的fptr的值,如果其不为所期望的值则说明:1.文件以只读打开,指针只能移动到文件结束处。2.磁盘满了。

 

示例:

fatfs源码阅读第6张

 


------------------------------------------------------------------------------------------------------------


F_truncate:

fatfs源码阅读第7张

 

缩短文件大小,将文件尾缩短到当前指针处,如果当前指针已经在文件末尾,则不会发生任何改变。

 

f_sync

fatfs源码阅读第8张

 

介绍这个函数之前先详细的说一下fatfsf_write的流程,此流程为读文件系统代码得出:

准备开始写,先查看一下当前的文件的字节数是不是512的整数倍,如果是的话再查看flag标志中,通过查看可以得出缓冲区是不是又一个完整扇区的数据,如果有的话先将缓冲区中一个扇区的数据写入sd卡,写入512*最大整数倍的数据。剩下的存入缓冲区中。

准备开始写,先查看一下当前的文件的字节数是不是512的整数倍,如果不是,说明缓冲区中还有部分数据,那么就用要写入的数据中的一部分填满缓冲区,更新flag标志,然后回到上一段文字。

 

那么也就说我们不断操作的过程中,其实有可能有一部分文本信息并未真正的写入sd卡中,而是存储在文件的buf数组也就是缓冲区里。那么f_sync的作用就是把缓冲区的数据强制写入sd卡中,这样的话,如果写入文件的持续时间长,周期性的的f_sync一次,可以尽量的保证断电等意外突发情况数据损失减小。

  

对,你没猜错,f_close函数中会调用这个函数以保证关闭文件之后所有数据均以写入sd卡。所以这个函数利f_close唯一的区别就在于函数调用之后文件不失效。

 

因为sd卡每次最少写入512字节,所以这次写入不足512字节,那么就用无用的数据填补够512字节,而这部分数据其实还留在缓冲区,下次再写的时候直接用新的数据将这次不足的还有一部分无用信息的数据覆盖掉。(本段为猜测)

 

 

F_opendir

fatfs源码阅读第9张

 

可以打开一个目录,也可以创建一个目录。该目录对象可以不经过任意函数直接丢弃。

 

f_readdir

fatfs源码阅读第10张

 

读取一个目录中的项目(这个项目可能是个文件,也可能是个目录),将返回的这一个项目的信息存在FILINFO中,一次返回一个,不停的重复调用这个函数,就能得到这个目录下所有项目的信息了。当读完之后,再次调用这个函数,FILINFO中的f_name属性为空,可以此来判断是不是读取完了所有的该目录下的项目。

   注:fatfs支持长文件名,需_USE_LFN宏为真,FILINFO数据结构中有相应的属性处理长文件名。FILINFO数据结构如下:

fatfs源码阅读第11张

 

   

使用示例:

fatfs源码阅读第12张 

 f_getfree

fatfs源码阅读第13张

 

    这个函数使用来得到空闲的簇的的数目并把文件系统的信息通过第三个参数返回。通过文件系统数据结构的属性同样能计算出空闲的簇数。

 

f_stat

fatfs源码阅读第14张

 

获取一个文件或者目录的相关信息。返回到FILINFO结构体中。

 

f_mkdir:

fatfs源码阅读第15张

 

就是新建一个目录。

用法如下:

fatfs源码阅读第16张

 

 

 

f_unlink

fatfs源码阅读第17张

 

    删除一个文件或者目录,但要注意以下几点:

1.文件或者目录不能使只读的。

2.目录的话一定要是空的并且不能是当前目录。

3.文件的话不能是打开的。

 

f_chmod

fatfs源码阅读第18张

 

    第一个参数:文件名

第二个参数:待被设置的属性标志

第三个参数:要被修改的属性标志

 

首先文件的属性有以下几种:

fatfs源码阅读第19张

 

那么这个函数的第二个参数和第三个参数是什么意思呢?第二个参数是指函数要把文件要设置成那种属性,第三个参数是指函数要修改那些属性,也就是说出现在第三个参数而没有出现在第二个参数就是要清除的标志,比如:

fatfs源码阅读第20张

 

就是代表设置只读标志,清除读档标志。

 

 

f_utime

fatfs源码阅读第21张

 

修改一个目录的时间戳,把想要修改成的数据通过第二个参数传入。

使用例子:

fatfs源码阅读第22张

 

 

 

f_rename

fatfs源码阅读第23张

 

    可以用来重命名一个文件,也可用来移动一个文件,如下:

fatfs源码阅读第24张

 

    注意,移动文件不能跨设备移动,比如sd卡的文件只能在sd卡内移动,也不能移动一个已经打开的文件。

 

f_chdir

fatfs源码阅读第25张

 

     修改某个设备的当前目录。当设备初始打开的时候,当前目录自动设置为根目录。用例如下:

fatfs源码阅读第26张

 

 

f_chdrive

fatfs源码阅读第27张

 

修改当前设备。初始的当前设备为0号设备。

 

 

f_getcwd

fatfs源码阅读第28张

 

恢复当前设备上的当前目录。

 

 

f_forward:(看的很粗)

fatfs源码阅读第29张

 

 

从文件中读取数据并直接将数据转发到输出流,而不使用数据缓冲区,适用于小存储系统。

 

 

f_mkfs

fatfs源码阅读第30张

 

     新建一个文件系统,其实感觉主要作用是格式化。

 

 

f_fdisk:(没好好看)

fatfs源码阅读第31张

 

分区,最多可以分四个,创建分区表到设备的MBR

 

 

以下函数大概介绍一下:

 

fatfs源码阅读第32张

 

     这四个输入输出函数,前三个封装的是f_readf_write,最后一个封装的是f_putcf_puts

 

 

f_tell

fatfs源码阅读第33张

 

得到当前的读写指针,其实是一个宏,如下:

fatfs源码阅读第34张

 

 

f_eof

fatfs源码阅读第35张

 

检查当前的读写指针是否打到了文件结尾。

fatfs源码阅读第36张

 

 

f_size

fatfs源码阅读第37张

 

又是一个宏,返回的是文件大小。

fatfs源码阅读第38张

 

 

 

f_error

fatfs源码阅读第39张

 

测试文件是否出错。同样是个宏。

fatfs源码阅读第40张

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 




来自为知笔记(Wiz)


免责声明:文章转载自《fatfs源码阅读》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇(转)Should 断言的基本使用方法DRF接口操作--群增,群更,群删下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

数据结构与算法80道

1. 把二元查找树转变成排序的双向链表 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。    10  /  6 14  / / 4 8 12 16  转换成双向链表 4=6=8=10=12=14=16。   首先我们定义的二元查找树 节点的数据结构如下:  struct BSTreeN...

第一章 绪论

1.1数据结构的讨论范畴 Pascal语言的创始人 Niklaus Wirth 教授提出过大名鼎鼎的程序设计公式                                                                                     Algorithm + Date_Structures = Programs...

自己动手设计并实现一个linux嵌入式UI框架(设计)

  看了“自己动手设计并实现一个linux嵌入式UI框架”显然没有尽兴,因为还没有看到庐山真面目,那我今天继续,先来说说,我用到了哪些知识背景。如:C语言基础知识,尤其是指针、函数指针、内存分布,linux 基础知识、如消息队列、framebuffer、多线程、多线程同步、等,数据结构、算法(如链表、队列等),window .netframework 框架...

数据结构-树

树的存储结构 1.双亲数组存储结构 用一个一维数组存储树中的各个节点,数组元素是一个记录,包含data和parent两个字段,分别表示节点的数据值和其双亲在数组中的下标。其类型定义如下: typedef struct { ElemType data; int parent; } ParType[MaxSize]; 在这个一维数组中,树...

数据结构(二):链表、链队列

上一篇博文中主要总结线性表的顺序存储结构实现,比如顺序表、顺序队列和顺序栈。具体可以参考上篇博文 http://blog.csdn.net/lg1259156776/article/details/46993591 下面要进行学习和总结的是线性表的链式存储结构实现,比如链表和链队列。 顺序存储结构的优缺点优点是逻辑相邻,物理相邻,可随机存取任一元素,存...

RedisTemplate访问Redis数据结构(四)——Set

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据,Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 SetOperations提供了对无序集合的一系列操作。首先初始化spring工厂获得redisTemplate和opsForSet private RedisTempl...