前序

文件系统的最终目的是为了进行文件的管理,文件的管理就是读写、删除等操作,文件打开后,本篇继续分析读操作。

分析假设

(1)假设一个磁盘就一个分区。

(2)只分析FAT32文件系统相关的代码。

(3)函数的大部分分析,都写入代码注释中。

(4)重要的注释都回加入很多星号以及数学标号。例如,
/****************** 1.把字符存入lfn的buffer中 *******************/
(5)在f_open()分析时,发现太多的代码,占用了不少的位置,从此篇文章开始,删除错误判定和不重要的代码,减少文章的长度。

f_read函数分析

下面是f_read()函数的源码:

FRESULT f_read (FIL* fp,     /* Pointer to the file object */void* buff, /* Pointer to data buffer */UINT btr,   /* Number of bytes to read */UINT* br   /* Pointer to number of bytes read */
)
{FRESULT res;FATFS *fs;DWORD clst, sect;FSIZE_t remain;UINT rcnt, cc, csect;BYTE *rbuff = (BYTE*)buff;*br = 0;    /* Clear read byte counter *//********* 1.如果文件可读数据不足,调整要读取的数据字节数 **********/remain = fp->obj.objsize - fp->fptr;if (btr > remain) btr = (UINT)remain;        /* Truncate btr by remaining bytes */for ( ;  btr;                              /* Repeat until all data read */rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {if (fp->fptr % SS(fs) == 0) {            /* On the sector boundary? */csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));    /* Sector offset in the cluster *//* 够了一个正簇,需要找到文件的下一个簇的位置 */if (csect == 0) {                    /* On the cluster boundary? */if (fp->fptr == 0) {         /* On the top of the file? */clst = fp->obj.sclust;     /* Follow cluster chain from the origin */} else {                      /* Middle or end of the file */if (fp->cltbl) {clst = clmt_clust(fp, fp->fptr);  /* Get cluster# from the CLMT */} else{clst = get_fat(&fp->obj, fp->clust);  /* Follow cluster chain on the FAT */}}fp->clust = clst;                /* Update current cluster */}sect = clust2sect(fs, fp->clust);  /* Get current sector */sect += csect;cc = btr / SS(fs);                 /* When remaining bytes >= sector size, *//************ 2.如果要读出的数据大于1个扇区,就先把整数扇区直接读入到用户的缓冲区 ****************/if (cc) {                          /* Read maximum contiguous sectors directly */if (csect + cc > fs->csize) {  /* Clip at cluster boundary */cc = fs->csize - csect;}if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));}rcnt = SS(fs) * cc;                /* Number of bytes transferred */continue;}/* fp缓冲区对应的sect值与要读的扇区不相同的话,先要把脏扇区回写到磁盘,再从磁盘把数据读入到fp对应的缓冲 */if (fp->sect != sect) {          /* Load data sector if not in cache */if (fp->flag & FA_DIRTY) {     /* Write-back dirty sector cache */if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);fp->flag &= (BYTE)~FA_DIRTY;}if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK)    ABORT(fs, FR_DISK_ERR); /* Fill sector cache */}fp->sect = sect;}rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);   /* Number of bytes left in the sector */if (rcnt > btr) rcnt = btr;                 /* Clip it by btr if needed *//******* 3.把不足一个扇区的内容,通过当前扇区的缓冲区,直接读入到用户缓冲区 ********/mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt);    /* Extract partial sector */}LEAVE_FF(fs, FR_OK);
}

读文件相对来说简单一些:
(1)找出文件所在的簇的起始位置,这个簇在f_open()函数的时候已经被确认了。
(2)然后在把簇中的内容读取到用户的缓冲区。

核心思想总结

(1)在f_open()函数的时候,fp->obj.objsize中记录的文件的大小,fp->clust记录了文件的起始簇号。
(2)每次读文件的时候都会更改fp->fptr的值,如果fp->fptr的值够了一个簇,但是要读取的大小还不足,此时就要找到文件对应的下一个簇的位置,然后更新fp->clust。

(3)在文件描述符的fp对应的结构体中,sect指向当前的读扇区,buf[]缓冲当前的扇区内容。

fatfs文件系统详解之f_read函数分析相关推荐

  1. fatfs文件系统详解之f_mkfs函数分析

    前序 前面两篇文章分析了FAT文件系统,没有代码总感觉很空虚寂寞冷,fatfs正好是一个开源专门应对fat文件系统的代码,从这篇文章开始分析fatfs代码,"理论+实践"才是悟道的 ...

  2. fatfs文件系统详解之f_mount函数分析

    前序 上一篇分析了格式化一个磁盘的时候发生了什么,在格式化一个磁盘之后,就要将磁盘进行挂载,"挂载"这个词听起来很抽象,但是在软件代码上,到底发生了什么? 分析假设 (1)假设一个 ...

  3. fatfs文件系统详解之f_write函数分析

    前序 本篇分析f_write()函数,fatfs文件系统对应的不知道文件的读写,也对应了文件的其他的操作,也有文件夹的操作,函数分析确实是一个非常耗时耗精力的事情,此函数分析完之后,就结束函数分析. ...

  4. FATFS文件系统详解

    一.文件系统 负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统.即在磁盘上组织文件的方法. 常用的文件系统: FAT / FATFS NTFS: 基于安全性的文件系统,是Windows ...

  5. 国产超低功耗华大单片启动文件详解及SystemInit函数分析

    启动代码文件名一般可命名为如startup_hc32xxxx.s.启动代码作用一般是: 1) 堆和栈的初始化 包括堆栈的大小,MSP(main stack pointer)值等.MSP的初始值在复位阶 ...

  6. 004:STM32启动文件详解及SystemInit函数分析(转)

    1 ;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000 2 ;然后在RAM中分配变量使用的堆 3 ;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x080 ...

  7. STM32启动文件详解及SystemInit函数分析

    1 ;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000 2 ;然后在RAM中分配变量使用的堆 3 ;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x080 ...

  8. Linux系统调用详解(实现机制分析)

    为什么需要系统调用   linux内核中设置了一组用于实现系统功能的子程序,称为系统调用.系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于内核态,而普通的函数调用由函数库或用户 ...

  9. [自制操作系统] JOS文件系统详解支持工作路径MSH

    本文分为两部分: 第一部分将详细分析JOS的文件系统及文件描述符的实现方法. 第二部分将实现工作路径,提供新的系统调用,完善用户空间工具. 本文中支持的新特性: 支持进程工作目录 提供getcwd与c ...

最新文章

  1. 基于SSM实现招聘网站
  2. centos6.7x86_64安装nginx (good)
  3. 动态规划/贪心总结(一)
  4. P3978 [TJOI2015]概率论
  5. 对爬虫数据分析的同学不要错过啦 数据分析数据可视化: Matplotlib
  6. hive case when语法_SQL中CASE表达式的妙用
  7. XX基金 机器学习平台使用情况访谈总结
  8. ios去掉字符串中的某个字符_iOS如何过滤掉文本中特殊字符
  9. SQL入门经典思维导图学习
  10. html php即时通讯_PHP在线客服即时通讯源码
  11. linux dump备份svn,svnadmin dump+load库中的某个目录用svndumpfilter 可实现
  12. PTA 基础编程题目集 7-15 计算圆周率 C语言
  13. web前端 “我是有底线的”效果
  14. 南卡NANK Runner CC3 耳机评测:骨传导耳机入门级别最强款
  15. Gradle sync failed: Could not find xxxx.xx 之 强制刷新Gradle dependencies
  16. 前端性能优化,之还在为多种多样的知识点整理苦恼吗,进来看看吧。
  17. Gitlab-Runner原理与实现
  18. opencv-python 立体图像的深度图
  19. 甜点cc的2022走心总结
  20. 蔡徐坤游戏HTML,JS制作蔡徐坤打篮球小游戏(鸡你太美?)

热门文章

  1. mybatis ew.sqlSegment @Param(“ew“)
  2. 循环彩灯定时器C语言,PLC基本指令及应用,学会控制彩灯,并循环往复工作
  3. 【说一千道一万】volatile关键字的作用和synchronized的关系
  4. html websocket
  5. 如何把FLAC+CUE刻录成CD
  6. larry wall
  7. React 性能优化完全指南,将自己这几年的心血总结成这篇!
  8. Day12 编码与文件的简单操作方法
  9. 将物流行业送往智能时代,菜鸟网络的配送车已经上路了
  10. 昆明理工大学知道计算机答案,昆明理工大学 计算机基础教材参考答案(1-6章)