您的位置:首页 > 文旅 > 美景 > 【FATFS】f_read函数详细解析

【FATFS】f_read函数详细解析

2024/10/6 6:05:42 来源:https://blog.csdn.net/W__winter/article/details/142268386  浏览:    关键词:【FATFS】f_read函数详细解析

FATFS f_read函数详细解析

    f_read 函数用于从打开的文件中读取数据,将读取到的数据存储在提供的缓冲区中。该函数的主要作用是从文件中读取指定数量的字节

FRESULT f_read (FIL* fp,    /* 打开的文件对象指针 */void* buff,	/* 存储读取数据的缓冲区 */UINT btr,	/* 需要读取的字节数 */UINT* br	/* 实际读取的字节数(输出参数) */
)
{FRESULT res;              /* 操作结果,返回值 */FATFS *fs;                /* 文件系统对象指针 */DWORD clst;               /* 当前簇号 */LBA_t sect;               /* 当前扇区号 */FSIZE_t remain;           /* 文件剩余的字节数 */UINT rcnt, cc, csect;     /* 分别为:实际读取的字节数,连续读取的扇区数,当前簇中的扇区偏移 */BYTE *rbuff = (BYTE*)buff;/* 读取缓冲区指针,方便按字节操作 */*br = 0;	/* 初始化已读取字节数为 0 */res = validate(&fp->obj, &fs); /* 验证文件对象是否合法,获取文件系统对象 */if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) /* 如果文件对象无效或有错误,退出 */LEAVE_FF(fs, res); /* 返回错误状态 */if (!(fp->flag & FA_READ)) /* 检查文件是否打开为可读模式 */LEAVE_FF(fs, FR_DENIED); /* 如果文件不可读,返回 "拒绝访问" 错误 */remain = fp->obj.objsize - fp->fptr; /* 计算文件剩余未读取的字节数 */if (btr > remain) btr = (UINT)remain; /* 如果要读取的字节数超过文件剩余部分,则调整为剩余字节数 *//* 循环读取数据,直到读取完所需的字节数 */for (; btr > 0; btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) {	if (fp->fptr % SS(fs) == 0) { /* 判断是否位于扇区边界 */csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* 计算当前簇中的扇区偏移 */if (csect == 0) { /* 如果在簇的边界 */if (fp->fptr == 0) { /* 文件起始处的簇 */clst = fp->obj.sclust; /* 获取文件的第一个簇 */} else { /* 中间或文件结尾 */
#if FF_USE_FASTSEEKif (fp->cltbl) {clst = clmt_clust(fp, fp->fptr); /* 快速寻址模式,获取当前簇号 */} else
#endif{clst = get_fat(&fp->obj, fp->clust); /* 从 FAT 表中获取当前簇的下一个簇 */}}if (clst < 2) ABORT(fs, FR_INT_ERR); /* FAT 表损坏,簇号错误 */if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); /* 读取 FAT 表时发生磁盘错误 */fp->clust = clst; /* 更新当前簇号 */}sect = clst2sect(fs, fp->clust); /* 将当前簇转换为对应的起始扇区 */if (sect == 0) ABORT(fs, FR_INT_ERR); /* 扇区无效,返回内部错误 */sect += csect; /* 计算实际的物理扇区号 */cc = btr / SS(fs); /* 计算剩余字节数能读取的完整扇区数 */if (cc > 0) { /* 如果可以读取一个或多个完整扇区 */if (csect + cc > fs->csize) { /* 如果超过当前簇的边界 */cc = fs->csize - csect; /* 限制在当前簇范围内读取 */}if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); /* 直接从磁盘读取多个扇区到缓冲区 */
#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2
#if FF_FS_TINYif (fs->wflag && fs->winsect - sect < cc) {memcpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); /* 缓存中有脏扇区时,替换数据 */}
#elseif ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {memcpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); /* 替换缓存中的脏扇区数据 */}
#endif
#endifrcnt = SS(fs) * cc; /* 记录已传输的字节数 */continue; /* 跳过以下步骤,继续读取 */}
#if !FF_FS_TINYif (fp->sect != sect) { /* 如果要读取的扇区不在缓存中 */
#if !FF_FS_READONLYif (fp->flag & FA_DIRTY) { /* 如果缓存的扇区已被修改,需要写回 */if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* 将脏扇区写回磁盘 */fp->flag &= (BYTE)~FA_DIRTY; /* 清除脏标志 */}
#endifif (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* 将当前扇区读入缓存 */}
#endiffp->sect = sect; /* 更新当前的缓存扇区号 */}rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* 计算当前扇区中剩余的字节数 */if (rcnt > btr) rcnt = btr; /* 如果剩余字节数比需要读取的多,进行裁剪 */
#if FF_FS_TINYif (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* 移动扇区窗口 */memcpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* 从文件系统窗口中提取部分扇区数据 */
#elsememcpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* 从缓存中提取部分扇区数据 */
#endif}LEAVE_FF(fs, FR_OK); /* 成功退出并返回 */
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com