打印
[应用相关]

FatFsVersion0.01源码分析

[复制链接]
楼主: equivalent
手机看帖
扫描二维码
随时随地手机跟帖
21
externally| | 2019-7-22 15:57 | 只看该作者 回帖奖励 |倒序浏览
<2> 函数说明

@函数功能:以指定的方式打开或者新建一个文件。如果打开或者创建成功,

            会填充fp指向的文件信息变量(包含文件的目录项确切位置和文件的信息)。

@输入参数:fp              指向文件信息变量的指针

                 path         指向文件的路径

                 mode       打开方式

@输出参数:FR_OK      打开或者创建成功

               其他值  打开或者创建失败

<3> 备注

使用特权

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

① 以只读的方式打开一个已经存在的文件

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

     接下来就是从win[]中,将文件目录项的参数稍作转化后传入FIL类型的变量中。到此,一个文件就算完整的打开了。注意打开文件并不是打开文件的内容,而是文件的目录项,知道了文件的目录项就知道了如何去查看文件的内容。

     以后,通过FIL类型的变量就可以操作对应的文件。

② 新建一个文件

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

  首先给新建文件在当前文件夹中预定一个目录项位置,然后填入新建文件的目录项初始值(文件名、扩展名、属性、创建时间、更新时间)到win[]中。注意这里并不会将新建文件目录项所在扇区同步到磁盘中,只有当调用f_sync函数时才会将文件的目录项所在扇区同步到磁盘。

  创建一个新文件,只会在其上一层目录中添加对应的目录项并初始化,并不会给文件分配数据空间,当然文件的大小肯定是0。

③ 重建一个文件

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

  重建首先将文件的簇链删除,然后设置文件起始位置和文件大小为空,还需要初始化文件的属性、创建时间和修改时间。这里的修改都只是在win[]中进行的,并没有同步到磁盘。只有当调用f_sync函数时才会将文件的目录项所在扇区同步到磁盘。

  重建文件更改了原来文件在目录中的目录项信息,重建文件并没有分配簇,也就是没有分配数据空间。

使用特权

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

☆  以只读的方式打开一个已经存在的文件



☆  新建一个文件的过程

① 程序刚执行



② 程序执行中



③ 程序执行后

使用特权

评论回复
24
externally| | 2019-7-22 15:58 | 只看该作者
3、f_read

<1> 函数原型

FRESULT f_read (
         FIL *fp,             /* Pointer to the file object */
         BYTE *buff,          /* Pointer to data buffer */
         WORD btr,            /* Number of bytes to read */
         WORD *br             /* Pointer to number of bytes read */
)

使用特权

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

@函数功能 :文件读操作

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

                          buff  指向用户缓冲区

                          btr             准备读取的字节数

                          br               指向实际读取字节数的变量

@输出参数:FRESULT 成功与否

使用特权

评论回复
26
externally| | 2019-7-22 15:59 | 只看该作者
<3> 备注

       此函数在读取文件内容后,还会移动文件指针到下一此读写操作的起点。

使用特权

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

  读文件的情况有些复杂,不同的情况有不同的处理方法。在“<5>程序执行示意图”中,我展示了一种还算全面的情况,就以这种情况为例进行说明。开始读的时候,文件指针并没有位于扇区边界上(512字节对齐),读取的跨度为3个簇。

      首先读没有对齐扇区的剩余内容,其实这个内容在以前的函数(以前的函数移动了文件指针)已经将这个扇区的内容加载到了buffer中。所以,直接从缓冲区buffer中读取此扇区文件指针以后的剩余内容到用户缓冲区。

   接下来,读取第一个簇的剩余一个扇区的内容到用户缓冲区。通过get_cluster函数从FAT表中,获取第二个簇链的位置。然后一次性的将一个簇链的所有扇区内容读取到用户缓冲区中。再通过get_cluster函数从FAT表中,获取第三个簇链的位置。然后将第三个簇链的第一个扇区内容读取到用户缓冲区中。

  最后,将最后所需要读取剩余内容所在的扇区(剩余部分不够一个扇区)读取到buffer中,然后再从buffer中读取所需要的剩余内容到用户缓冲区中。到这里为止,整个读取操作已经完成。

  由于buffer中还有一部分内容没读,假设继续调用函数f_read函数读取数据,那么肯定先从这个buffer缓冲区中将文件指针以后的扇区剩余内容读取到用户缓冲区。

使用特权

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

使用特权

评论回复
29
externally| | 2019-7-22 16:00 | 只看该作者
4、f_write

<1> 函数原型

FRESULT f_write (
         FIL *fp,                        /* Pointer to the file object */
         const BYTE *buff,           /* Pointer to the data to be written */
         WORD btw,                       /* Number of bytes to write */
         WORD *bw                        /* Pointer to number of bytes written */
)

使用特权

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

@函数功能 :文件写操作,只对文件的数据区进行写入,并没有更新对应的目录项。

                 如果写入时,最后写入的数据字节没有完美的扇区对齐,那么肯定会将需要写入磁盘的一个扇区

              在文件缓冲区中进行缓存

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

                           buff   指向读取的用户缓冲区

                           btw           准备写入的字节数                        

                           bw             返回实际写入的字节数

@输出参数:FRESULT 成功与否

使用特权

评论回复
31
externally| | 2019-7-22 16:00 | 只看该作者
<3> 备注

  此函数在写完文件内容后,还会移动文件指针到下一此读写操作的起点。

使用特权

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

  写文件的情况与读取文件内容类似,不同的情况有不同的处理方法。在“<5>程序执行示意图”中,我展示了一个全面的情况,就以这种情况为例进行说明。开始写的时候,文件指针并没有位于扇区边界上(512字节对齐),写入数据的跨度为3个簇。

     首先写入没有对齐扇区的剩余内容,其实这个内容在以前的函数(以前的函数移动了文件指针)已经将这个扇区的内容加载到了buffer中。所以,将用户缓冲区中对应的内容写入到buffer中(从文件指针开始到buffer结束的这部分空间)。然后再将buffer中的内容写入到磁盘对应的扇区。

  接下来,将用户缓冲区写入到第一个簇的剩余一个扇区中。通过creat_chain函数从FAT表中,获取第二个簇链的位置(如果是文件有剩余簇链则使用文件的剩余簇链,如果已经用完则重新从FAT表中搜索一个空的簇链连接到此文件中,也就是更改了文件的大小)。然后一次性的将用户缓冲区写入到第二个簇链的所有扇区中。再通过get_cluster函数从FAT表中,获取第三个簇链的位置。然后将用户缓冲区写入到第三个簇链的第一个扇区中。

  最后,将最后所需要写入剩余内容所在的扇区(剩余部分不够一个扇区)读取到buffer中,然后再将用户缓冲区中剩余内容写入到buffer中。到这里为止,整个读取操作已经完成。注意这里并没有将buffer的内容写入到磁盘中。当调用f_sync函数的时候才会将buffer的内容同步到磁盘。

  在函数返回之前,还需要判断文件大小是否更改了,如果大小更改了则要更新文件的大小,并将FA__WRITTEN记录到文件的flag中。这样做的目的是为了当执行f_sync时,可以根据FA__WRITTEN判断出文件修改过,从而更新文件的目录项。

☆  假设

  由于buffer中还有一部分内容没操作,
假设1:继续调用函数f_write函数写入数据

  那么肯定先将用户缓冲区的内容写入到这个buffer缓冲区中。只有超出了buffer缓冲区的范围,才会将这个buffer缓冲区的内容同步到磁盘,并且读取下一个扇区的内容到buffer中(假设文件指针仍然没有对齐)。

假设2:调用函数f_read函数读取数据
  先从这个buffer缓冲区中将文件指针以后的扇区剩余内容读取到用户缓冲区,而不会从磁盘中读取。

☆  总结
  buffer的妙处,提高了读写的效率,避免了重复读写磁盘。

使用特权

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

使用特权

评论回复
34
externally| | 2019-7-22 16:01 | 只看该作者
5、f_sync

<1> 函数原型

FRESULT f_sync (
         FIL *fp                /* Pointer to the file object */
)

使用特权

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

@函数功能 :在关闭文件之前,同步文件缓冲区中的内容到磁盘,同步文件目录项信息到磁盘

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

@输出参数:FRESULT 成功与否

<3> 备注

使用特权

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

       判断文件是否修改过,如果修改过再判断文件buffer缓冲区是否修改过,如果修改过则同步到磁盘中文件对应的数据空间中。如果文件修改过,还要更新文件的目录项,这时的修改也是在win[]中的。

       最后通过调用move_window(0),将文件目录项信息同步到磁盘中。

使用特权

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

使用特权

评论回复
38
externally| | 2019-7-22 16:02 | 只看该作者
6、f_opendir

<1> 函数原型

FRESULT f_opendir (
         DIR *scan,            /* Pointer to directory object to initialize */
         const char *path      /* Pointer to the directory path, null str means the root */

)

使用特权

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

@函数功能 :打开一个目录

@输入参数: scan:指向返回找到的目录项结构体

                  path  指向路径

@输出参数:FRESULT 成功与否

<3> 备注

使用特权

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

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

     接下来判断找到的是不是一个目录。如果就是一个目录的话,就从win[]中将目录对应目录项的参数稍作转化后传入DIR类型的变量中。到此,一个目录就算完整的打开了。注意打开目录并不是打开目录的内容,而是目录对应的目录项,知道了目录对应的目录项就知道了如何去查看目录的内容。

     以后,通过DIR类型的变量就可以操作对应的目录。

使用特权

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

本版积分规则