打印
[应用相关]

FatFsVersion0.01源码分析

[复制链接]
楼主: equivalent
手机看帖
扫描二维码
随时随地手机跟帖
41
externally| | 2019-7-22 16:03 | 只看该作者 回帖奖励 |倒序浏览
<5> 程序执行示意图

使用特权

评论回复
42
externally| | 2019-7-22 16:03 | 只看该作者
7、f_mkdir

<1> 函数原型

FRESULT f_mkdir (
         const char *path               /* Pointer to the directory path */
)

使用特权

评论回复
43
externally| | 2019-7-22 16:04 | 只看该作者
<2> 函数说明

@函数功能 :创建一个目录

         注意:新建一个目录,它虽然是一个空目录(有效存储内容为0),但是

         系统已经为它分配了一个簇的数据空间,用于保存它的目录项。这是与新建一个

         普通文件区别很大的地方。

         另外,新建一个目录时,对新建目录在上一层目录的目录项以及新建目录中的目

         录项的初始化,全部都在win[]中进行操作。

@输入参数:          path  指向路径的指针

@输出参数:FRESULT 成功与否

<3> 备注

使用特权

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

  首先调用函数trace_path搜索文件系统中是否存在目标目录,因为是新建目录肯定不存在。那么不存在目录时就返回新建目录所在当前文件夹的目录指针(dirscan、dir)--第一个空目录项位置,并且将当前目录指针所在扇区的内容加载到win[]中。

  接下来给新建目录在当前文件夹中预定一个目录项位置。然后调用creat_chain函数在FAT表中为新建目录找到一个可用的数据簇,再调用move_window(0)同步FAT表到磁盘中。为新建目录的数据簇初始化,并且初始化第一个目录项。最后,填入新建目录的目录项初始值(目录名、属性、创建时间 、数据簇起始位置)到win[]中。然后同步到磁盘中,完成整个新建目录的工作。

☆  注意

<1> 创建一个新目录,不仅会在其上一层目录中添加对应的目录项并初始化,并且会给新建目录分配一个簇的数据空间,并进行初始化。

<2> 新建一个目录时,会将新建目录的数据簇和对应目录项所在扇区都同步到磁盘中,这与文件必须通过调用f_sync才能同步是不一样的。

<3> 新建一个目录会给目录分配数据空间,而新建文件则是没有的,这也是一个巨大的差别。

<4> 新建一个目录的所有操作都是在win[]中进行的,不管是新建目录的对应目录项,还是新建目录的数据空间都是在win[]中进行的。

使用特权

评论回复
45
externally| | 2019-7-22 16:05 | 只看该作者
<5> 程序执行示意图

① 程序刚执行



② 程序执行中



③ 程序执行后

使用特权

评论回复
46
externally| | 2019-7-22 16:05 | 只看该作者
8、f_unlink

<1> 函数原型

FRESULT f_unlink (
         const char *path                         /* Pointer to the file or directory path */
)

使用特权

评论回复
47
externally| | 2019-7-22 16:05 | 只看该作者
<2> 函数说明

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

           1、删除目录或者文件的簇链(回收数据空间)

           2、文件或者目录的目录项被设置成为删除(0xE5),注意目录项并没有回收,只是标记为删除

@输入参数: path  指向路径的指针

@输出参数:FRESULT 成功与否

<3> 备注

使用特权

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

  首先调用函数trace_path搜索文件系统中是否存在所要删除的目录或者文件,如果不存在就返回失败;如果存在就返回对应目录项的位置(dirscan、dir),并且将对应目录项所在扇区的内容加载到win[]中。

      判断要删除的是不是目录,如果是目录还要判断是不是非空目录,如果是非空目录则不允许删除。如果是空目录,那么就可以删除。

      删除文件或者目录时,首先删除簇链(数据空间),然后修改目录项为删除状态(0xE5),最后同步目录项所在扇区win[]缓冲区到磁盘中,完成删除。   

使用特权

评论回复
49
externally| | 2019-7-22 16:06 | 只看该作者
<5> 程序执行示意图

① 程序刚执行



② 程序执行中



③ 程序执行后

使用特权

评论回复
50
externally| | 2019-7-22 16:06 | 只看该作者
9、f_lseek

<1> 函数原型

FRESULT f_lseek (
         FIL *fp,              /* Pointer to the file object */
         DWORD ofs               /* File pointer from top of file */
)

使用特权

评论回复
51
externally| | 2019-7-22 16:07 | 只看该作者
<2> 函数说明

@函数功能 :移动文件指针,实际上就是修改文件指针(当前簇号、当前扇区号、文件指针fptr)

@输入参数: fp    文件信息指针

              ofs 定位文件指针的位置(从文件头部开始的偏移量)

@输出参数: fp 返回重新定位后的文件信息(包含文件指针)

                  FRESULT 成功与否

<3> 备注

使用特权

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

     首先要对缓冲区buffer进行同步,因为文件指针中的curr_sect代表的是当前处在buffer中物理扇区号。现在要移动指针,也就是要移动当前扇区号curr_sect,所以要先将buffer进行同步。

  偏移量进行修正,因为可能偏移量超过了文件的大小,修正后的偏移量直接赋给fptr。

     接下来根据偏移量,结合着当前的文件信息FIL类型的对象计算出移动指针后的簇号、扇区号。倘若移动后的文件指针没有512字节对齐,则还需要将curr_sect指向的物理扇区内容读取到buffer中。这样接下来的文件读写操作才不会出错。

使用特权

评论回复
53
externally| | 2019-7-22 16:08 | 只看该作者
<5> 程序执行示意图

① 程序执行前



② 程序执行中和程序执行后

使用特权

评论回复
54
externally| | 2019-7-22 16:08 | 只看该作者
10、f_readdir

<1> 函数原型

FRESULT  f_readdir (
         DIR *scan,               /* Pointer to the directory object */
         FILINFO *finfo           /* Pointer to file information to return */
)

使用特权

评论回复
55
externally| | 2019-7-22 16:08 | 只看该作者
<2> 函数说明

@函数功能 :从当前目录项指针处读取一个目录项,并且移动目录指针到下一个索引

@输入参数: scan:要读取的目录

                  finfo 目录的信息

                       finfo->fname[0] = 0           :这是一个空目录项

                       finfo->fname[0] = others :这是一个非空目录项

@输出参数:FRESULT 成功与否

<3> 备注

使用特权

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

         首先将目录指针当前所在物理扇区读取到win[]中,然后调用get_fileinifo函数从当前目录指针处读取当前目录项并处理后存入finfo中。最后,还要移动目录项指针到下一个索引位置。

使用特权

评论回复
57
externally| | 2019-7-22 16:09 | 只看该作者
<5> 程序执行示意图

① 程序执行



② 程序执行后

使用特权

评论回复
58
externally| | 2019-7-22 16:10 | 只看该作者
四、FATFS文件系统解惑

1、win[]和buffer

     文件系统用了两种重要的缓冲区win[]和buffer。这两种缓冲区的用途在第二章和第三章中已经阐述。但是深层次的思考,它们对应磁盘扇区的读写时机是什么?也即是说什么时候需要从磁盘中读取数据以更新缓冲区,又什么时候需要将缓冲区中的内容同步到磁盘。

     常见的磁盘比如说SD卡、硬盘,它们的扇区大小512字节,对磁盘进行一次读写的字节数要是512的倍数,而非随意的几个字节都可以。

buffer的魅力:

  如果文件系统设计成这样:从当前文件指针处,读取2个字节到用户缓冲区,需要将磁盘对应的扇区读一次;再次读2个字节到用户缓冲区,又从磁盘的对应扇区读一次,那么效率肯定很慢,频繁的读取相同的扇区是一件很蠢的事。

  在第二次读2个字节到用户缓冲区中的时候,可以看看需要的数据是否就处于buffer缓冲区中(第一次已经将一个扇区读如buffer),如果在就直接从buffer中读,如果不在再从磁盘中读。显然,这样做可以避免重复读取相同的扇区,只有到了迫不得已的时候才会读取磁盘其他的扇区。这样做提高了系统的效率。

  对于写文件时,buffer的作用也是类似的:第一次写入2个字节,需要先将文件指针对应磁盘的扇区读入buffer,然后通过用户缓冲区修改对应2个字节的内容;第二次写入2个字节的时候,如果写入的位置仍然在当前扇区的话,可以直接将用户缓冲区的内容替换掉接下来的2个字节的内容………如果迫不得已需要更换扇区,那将缓冲区中的内容同步到磁盘中,然后读入下一个扇区的内容到缓冲区中。

win[]的魅力:

     操作win[]最底层的函数move_window,如果读取的扇区号不变那么没必要重新读取磁盘。如果读取扇区号改变了,先将win[]同步到磁盘,然后读取另外一个扇区的内容到win[]中。

  这样的好处就是:假设我们如果不需要切换扇区,只对一个扇区进行读写操作。只在第一次读写的时候,将磁盘的内容读取到缓冲区中,接下来的读写操作实际上只是在缓冲区中进行的,而并没有实时的同步到磁盘中。一旦当我们切换扇区号的时候,就将win[]中的数据同步到磁盘中。显然,这样的效率很高,要比每一次都同步到磁盘中快的多。

缓冲区在常见情况的功效:

     通常我们读写一个文件,都不是一下很大范围的操作看,经常都是局部范围的读写。局部范围的读写只在第一次读写时,将磁盘中的数据读取到缓冲区中,接下来的操作全部都在缓冲区中进行。最后同步文件时,才将缓冲区的内容写入到磁盘。

总结:

  win[]和buffer作为磁盘到用户空间之间的过渡桥梁,使得用户的零碎读写操作,变成了磁盘的整存整取操作,提高了文件系统的效率。

  缓冲区算法实现关键:命中缓冲区就用缓冲区的操作,没命中替换缓冲区。

使用特权

评论回复
59
externally| | 2019-7-22 16:10 | 只看该作者
2、无缓冲区模式

     FatFs可裁剪成无缓冲区模式的文件系统,也就是阉割掉buffer,但win[]仍然需要。这样对于内存小的MCU来说,是一件非常有益的事情,当然也会为之付出代价—--不能零存领取。

     没有buffer,这样用户空间和文件数据空间是直通的,读写一次至少512字节,所以用户的操作都必须是512字节对齐的,也就是说文件指针要512字节对齐,而不像有buffer那样的任意数值。

     由于DBR/FAT/目录项这些参数的修改,必须是零存领取,所以win[]就必须需要了。

使用特权

评论回复
60
externally| | 2019-7-22 16:10 | 只看该作者
3、_FS_READONLY模式

     Readonly模式,也就是用户对于磁盘只有读取数据的需要,而没有写磁盘的要求。这种模式,阉割了代码量,对于ROM比较小的MCU来说也是一件非常有益的事情。但是这种模式对于减少RAM消耗量却起不到大的作用,要想减少RAM只能使用无缓冲buffer的模式。

使用特权

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

本版积分规则