打印
[应用相关]

FatFsVersion0.01源码分析

[复制链接]
3191|66
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
equivalent|  楼主 | 2019-7-22 15:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
目录
一、API的函数功能简述
二、FATFS主要数据结构
  1、FAT32文件系统的结构
  2、FATFS主要数据结构
    ①   FATFS
    ②   DIR
    ③  FIL
    ④  FILINFO
    ⑤  win[512]
    ⑥  buffer
三、函数功能与实现详细分析
   0、move_window
   1、f_mountdrv
   2、f_open
  3、f_read
  4、f_write
  5、f_sync
  6、f_opendir
  7、f_mkdir
  8、f_unlink
  9、f_lseek
  10、f_readdir
四、FATFS文件系统解惑
  1、win[]和buffer
  2、无缓冲区模式
  3、_FS_READONLY模式
五、FATFS文件系统函数使用注意事项

使用特权

评论回复
沙发
equivalent|  楼主 | 2019-7-22 15:49 | 只看该作者
一、API的函数功能简述

1、  FRESULT f_open (FIL*, const char*, BYTE);                        

函数功能:打开或者创建一个文件

2、FRESULT f_read (FIL*, BYTE*, WORD, WORD*);                        

函数功能:读一个文件

3、FRESULT f_close (FIL*);                                                                     

函数功能:关闭一个文件

4、FRESULT f_lseek (FIL*, DWORD);                                             

函数功能:移动文件的指针

5、FRESULT f_opendir (DIR*, const char*);                              

函数功能:读一个目录中的目录项

6、FRESULT f_readdir (DIR*, FILINFO*);                                             

函数功能:读取目录的内容

7、FRESULT f_stat (const char*, FILINFO*);                             

函数功能:获取文件的状态

8、FRESULT f_getfree (DWORD*);                                                        

函数功能:获得可用簇的数量

9、FRESULT f_mountdrv ();

函数功能:初始化文件系统

10、FRESULT f_write (FIL*, const BYTE*, WORD, WORD*);

函数功能:写文件

11、FRESULT f_sync (FIL*);                                                                     

函数功能:同步文件缓冲区的内容到磁盘中

12、FRESULT f_unlink (const char*);      

函数功能:删除一个文件或者目录

13、FRESULT   f_mkdir (const char*);                                                   

函数功能:创建一个目录

14、FRESULT f_chmod (const char*, BYTE, BYTE);        

函数功能:更改文件的属性

使用特权

评论回复
板凳
equivalent|  楼主 | 2019-7-22 15:49 | 只看该作者
二、FATFS主要数据结构

1、FAT32文件系统的结构



  概念与分区功能简述:

MBR:

  保存了磁盘的分区信息(分区的起始地址、分区大小、分区结束地址)

DBR:

  保存了当前分区的详细参数(比如FAT表的位置、FAT表的的大小、簇大小、扇区大小、根目录中最大目录项数等等)

FAT表:

  以簇的形式对数据区重新划分空间,在FAT表中建立了簇的使用情况,哪些已经被占用,哪些没有被占用;簇链的结构,也即是簇与簇之间的连接关系。

目录:

  在目录中,存在众多的目录项,目录项记录了文件名、大小、起始地址等等。

目录项:

  目录中的存储单位,记录了每一个文件或者目录的信息。

数据区:

  数据区中纯粹的文件数据

扇区:

  SD卡最小的读写单位,512字节,也就是说一次最少读取或者写入的数据是512字节。

☆  说明

<1> 有些SD卡格式化后,并没有MBR部分,而且SD卡格式化后磁盘上只存在一个磁盘分区。也就是说,即使SD卡上有MBR部分,在MBR的DPT(硬盘分区表)中也只有一个分区记录。

<2> 位于数据区之前的可以称之为文件系统管理区,此区域是以物理扇区为单位进行管理的,数据区则是以簇为单位进行管理的。

使用特权

评论回复
地板
equivalent|  楼主 | 2019-7-22 15:49 | 只看该作者
笔者认为1:

  狭义上的文件专指普通文件,目录则是位于普通文件的上层,用于管理处在其中的文件或者目录栏。笔者认为广义上的文件包含”目录和普通文件”。这样说目录,表示目录实际上也是一个文件,只不过是一个管理文件信息的特殊文件。

  可以说文件与目录既有区别,又有联系。普通文件在文件管理的时候,给文件设计了一个管理变量—文件指针,用于指示文件当前读取或者写入的位置,它是以字节为单位进行计算的;而目录其实也有一个管理读取或者写入的位置的变量—目录指针,它则是以目录项(32字节)为单位进行计算的。

笔者认为2:

  文件 = 目录中的目录项、FAT表、文件对应的数据区内容

<1> 查看磁盘信息就是查看DBR和FAT表

<2> 读取文件就是查看目录项、FAT表和文件对应的数据区内容

<3> 写文件就是修改目录项、FAT表、文件对应的数据区内容

使用特权

评论回复
5
equivalent|  楼主 | 2019-7-22 15:50 | 只看该作者
2、FATFS主要数据结构

①   FATFS

功能:保存了SD卡和文件系统的信息,主要是记录了DBR中的信息
/* 文件系统对象 */
typedef struct _FATFS {
    BYTE    fs_type;        // FAT文件系统的类型
    BYTE    files;          // 当前操作的文件数
    BYTE    sects_clust;    // 每簇扇区数
    BYTE    n_fats;         // FAT表个数
    WORD    n_rootdir;      // 根目录中的目录项项数
    BYTE    dirtyflag;      // 当前存储在win[]中的内容是否修改过
   
    BYTE    pad1;
    DWORD    sects_fat;      // 每个FAT表的扇区数
    DWORD    max_clust;      // Maximum cluster# + 1
    DWORD    fatbase;        // FAT起始扇区
    DWORD    dirbase;        // 根目录起始扇区
    DWORD    database;       // 数据区起始扇区
    DWORD    winsect;        // 保存在win[]中的当前扇区地址
    BYTE    win[512];        // 目录和FAT分配表的缓冲区
} FATFS;


拥有参数fats、sects_fat、fatbase、dirbase、database、sects_clust就知道了文件系统的整个布局,就可以方便的访问文件系统的每一部分。

使用特权

评论回复
6
equivalent|  楼主 | 2019-7-22 15:50 | 只看该作者
②   DIR

功能:作为目录项的指针,既可以用于记录一个特定文件在目录中的位置,又可以用于记录在目录中当前目录项指针的位置(类似与文件指针)。
typedef struct _DIR {
    DWORD    sclust;      // 目录起始簇号
    DWORD    clust;       // 当前簇号
    DWORD    sect;        // 当前扇区地址(物理扇区地址)   
    WORD    index;        // 当前索引(目录中的逻辑索引)
                          // 需要强调一点:索引是从目录的开始地址算起,每32Bytes加1,而且即使
                          // 切换扇区和簇,index也不会从0开始重新计数;只有当切换目录时,才会
                          // 重新清零
} DIR;


☆  说明

<1 > 记录特定文件在目录中的位置只需要sect和index

<2> 用于记录目录的位置只需要sclust;记录目录指针则需要clust、sect、index。

□  本文规定

  本文所说的目录指针指的是目录的当前目录项位置,有clust、sect、index构成完整的目录指针。

使用特权

评论回复
7
equivalent|  楼主 | 2019-7-22 15:51 | 只看该作者
③  FIL

功能:记录普通文件(不是目录文件)的详细信息,比如文件对应的目录项位置,文件起始簇号,文件指针,文件大小等。

typedef struct _FIL {
    DWORD    fptr;            // 文件指针,从文件的起始地址开始,以字节为单位计算
    DWORD    fsize;         // 文件大小
    DWORD    org_clust;       // 文件起始簇号
    DWORD    curr_clust;     // 当前簇号
    DWORD    curr_sect;       // 当前扇区地址,buffer缓冲区中存储的是该扇区的内容
#ifndef _FS_READONLY

    DWORD    dir_sect;        // 文件对应的目录项所在扇区号
    BYTE*    dir_ptr;         // 目录项在win[]中的入口地址
   
#endif
    BYTE*    buffer;          // 指向文件读写缓冲区(512字节)
    BYTE    flag;             // 文件状态标识
    BYTE    sect_clust;       // 当前簇中剩余扇区数
} FIL;


☆  说明

<1> dir_sect、dir_ptr记录了文件对应在目录中目录项的位置

<2> org_clust记录了文件的起始簇号

<3> fptr为文件指针,记录了文件当前读写的相对于开始处的偏移量(以字节为单位)

<4> curr_clust、curr_sect、sect_clust实际上也是文件读写指针,只不过它记录的是物理偏移量,结合着fptr就可以在物理磁盘上确定文件指针的确切位置。

□  本文规定

  本文所说的文件指针在不同的语境中有两种含义:广义的文件指针指fptr、curr_clust、curr_sect、sect_clust,狭义的文件指针专指fptr。

使用特权

评论回复
8
equivalent|  楼主 | 2019-7-22 15:51 | 只看该作者
④   FILINFO

功能:常用于需要获取文件参数的函数中,该结构体用于保存文件的属性,比如说文件的大小、创建时间、文件名字等。
typedef struct _FILINFO {
    DWORD fsize;            // 文件大小
    WORD fdate;             // 日期
    WORD ftime;             // 时间
    BYTE fattrib;           // 属性
    char fname[8+1+3+1];    // 名字(8.3 格式)
} FILINFO;


☆  Fname保存了文件的名字,但是是8.3格式的,这与它在目录项中存储的文件名不一样。

使用特权

评论回复
9
equivalent|  楼主 | 2019-7-22 15:52 | 只看该作者
⑤  win[512]

  位于FATFS结构体中,作为目录项或者FAT分配表的读写缓冲区。它不是某一个文件专有的缓冲区,而是整个文件系统的公共读写缓冲区。

<1> 当读取MBR、DBR的内容时,就需要借助于这个系统缓冲区。

<2> 当读写FAT表时,也需要将磁盘中FAT表的数据读取到该缓冲区中,或者将缓冲区中的内容写入到磁盘对应的扇区中。

<3> 当读写某一文件的信息(而非文件的数据时),就需要在此缓冲区中操作。而读写另外一个文件的信息时,则需要将上一个文件在缓冲区中的内容视情况同步到磁盘中,然后加载此文件的目录项对应扇区内容到缓冲区win[512]中。

<4> 文件包含对应的目录项和数据空间。目录项需要在win[]中操作在第<3>点已经说明了,而文件的数据空间的操作,则是交给了用户缓冲区,用户通过用户缓冲区读写文件的内容。文件的数据空间,有时也会通过文件的buffer与用户空间打交道。这将在⑥中进行讲述。

<5> 目录的操作全部都是在这个缓冲区中操作的,应用程序层也不会为目录开辟数据空间,所以目录的数据缓冲空间就是在这个缓冲区。需要注意的是:目录(目录文件)包含目录项(记录于上一层目录中)和数据空间,它的数据空间又担当了保存目录项的功能。不管是目录的目录项,还是目录的数据空间全部使用win[]缓冲区操作。

使用特权

评论回复
10
equivalent|  楼主 | 2019-7-22 15:52 | 只看该作者
⑥  buffer

  buffer是一个指向512字节缓冲区的指针,位于FIL结构体中,也就相当于是FIL中有一个512字节缓冲区的成员。此512字节的缓冲区,是一个文件的专有缓冲区。用于当文件的读写没有按照512字节对齐的时候,作为架接在磁盘与用户读写缓冲区之间的临时缓冲区。

使用特权

评论回复
11
equivalent|  楼主 | 2019-7-22 15:52 | 只看该作者
三、函数功能与实现详细分析

0、move_window

  这个函数不是一个可供用户调用的函数,是一个静态函数,只能被文件系统其他函数所调用。之所以首先讨论这个函数是因为它是唯一能够操作win[](系统缓冲区)的函数,其他的函数要想操作win[],必须通过调用此函数实现。

<1> 函数原型

BOOL move_window (
         DWORD sector                  /* Sector number to make apperance in the FatFs->win */

)   

使用特权

评论回复
12
equivalent|  楼主 | 2019-7-22 15:53 | 只看该作者
<2> 函数说明

@函数功能:win[]操作函数(DBR、FAT表、目录项)

      ① 读取新的扇区内容到临时缓冲区win[]

                 ② 同步win[]中的内容到磁盘

       注意:

              <1> 如果读取新的扇区号就是现在存储在win[]中的扇区号,就什么也不操作

              <2> 如果不同,则根据情况同步win[]到磁盘中,并且将新扇区中的内容读取到win[]中

           <3> 如果sector为0,则函数功能变为同步win[]到磁盘中,不会读取0扇区的内容到win[]

   @输入参数:sector 要读取扇区的扇区号

   @输出参数: 无

使用特权

评论回复
13
equivalent|  楼主 | 2019-7-22 15:53 | 只看该作者
<3> 备注

         此函数被下列函数所直接或者间接调用:

第一类:操作FAT表

① get_cluster

② put_cluster

③ remove_chain

④ create_chain

第二类:操作MBR、DBR

⑤ check_fs

第三类:操作目录项所在扇区(目录的数据空间)

⑥ trace_path

使用特权

评论回复
14
equivalent|  楼主 | 2019-7-22 15:53 | 只看该作者
<4> 程序实现方法简述

  首先判断要读取的扇区号是否与当前缓存在win[]中的扇区号一致。倘若一致,则无需执行任何操作。倘若不一致,再判断缓存在win[]中的内容是否被修改过,如果修改过,就需要更新到磁盘,最后还要把新扇区中的内容加载到win[]中。

     传入参数0,0与当前缓存在win[]的扇区号肯定不一样,所以一定会同步win[]内容到磁盘中。

使用特权

评论回复
15
equivalent|  楼主 | 2019-7-22 15:54 | 只看该作者
<5> 程序执行示意图

① 程序执行前



② 程序执行中



③ 程序执行后

使用特权

评论回复
16
equivalent|  楼主 | 2019-7-22 15:54 | 只看该作者
1、f_mountdrv

<1> 函数原型

FRESULT f_mountdrv ()

使用特权

评论回复
17
externally| | 2019-7-22 15:56 | 只看该作者
<2> 函数说明

@函数功能:

  1.初始化SD卡

  2、填充FatFs对象,即记录物理磁盘的相关参数

@输入参数 :无

@输出参数: 无

<3> 备注

使用特权

评论回复
18
externally| | 2019-7-22 15:56 | 只看该作者
<4> 程序实现方法简述

     首先调用SD卡初始化函数,对SD卡进行初始化。然后读取物理磁盘0号扇区的内容,判断是否是DBR扇区。如果不是DBR扇区,那么肯定就是MBR扇区,再从MBR扇区中获取DBR扇区的地址,将DBR扇区的内容调取到win[]中。

     接下来从win[]中,填充FatFs类型的系统对象,这样物理磁盘和文件系统的参数就被保存到了这个对象中。以后,程序就可以从全局变量--FatFs类型的变量,访问文件系统的每一个区域。

使用特权

评论回复
19
externally| | 2019-7-22 15:56 | 只看该作者
5> 程序执行示意图

使用特权

评论回复
20
externally| | 2019-7-22 15:56 | 只看该作者
2、f_open

<1> 函数原型

FRESULT f_open (
         FIL *fp,                       /* 指向文件结构体变量 */
         const char *path,              /* 指向文件路径 */
         BYTE mode                      /* 存取方式和打开方式 */

)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

274

帖子

0

粉丝