https://static.assets-stash.eet-china.com/album/old-resources/2010/3/19/4d5896ca-ef95-4cb2-9a40-906137442cad.rar有智林STM32开发板和SD卡的朋友可以下载测试。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
八、读文件执行流程分析续
上次的分析到了f_open()函数这个层次,到最后函数根据path所指向的文件填充了File信息结构体,最关键的信息包括文件目录项所在扇区、文件目录项指针、文件的起始簇号、文件读写指针当前位置、文件的访问模式等。
l 执行函数:f_read(&FileInf,(void *)FileBuf,500,&ByteRead);
FileBuf是用户提供的缓冲区,从文件读取的数据拷贝到它,500是每次想要读取的字节数,ByteRead是实际读出的数目。
进入函数,先执行remain = fp->fsize - fp->fptr;remain是文件从当前位置开始算还剩下的字节数。if (btr > remain) btr = (UINT)remain; 如果需读取数》实际剩余字节数,则改为把所有剩下的数字读完。
for ( ; btr; rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
//这里这个rcnt是每次能够读取的字节数,读取一次以后,用户缓冲区指针、文件读写指针都往前移动rcnt个季节,实际读取数加rcnt,剩下需要读取的数目减去rcnt。
if ((fp->fptr % SS(fp->fs)) == 0) { 第一次读文件时,指针指向0
if (fp->csect >= fp->fs->csize) { 第一次读文件csect=0xff。以后再读时,这个条件就不满足了。除非文件大于4K。
clst = (fp->fptr == 0) ? 这句执行完成后clst=文件数据区的第一簇。
fp->org_clust : get_fat(fp->fs, fp->curr_clust);
fp->curr_clust = clst; 更新文件所指向的当前簇
fp->csect = 0; 文件的当前扇区相对号为0.
}
sect = clust2sect(fp->fs, fp->curr_clust);将簇转换为实际的扇区号,在加上扇区相对号,就是实际扇区编号。
sect += fp->csect;
cc = btr / SS(fp->fs); 计算出需要读取的扇区的数目。
if (cc) { }这是大于或等于一个扇区的情况。
if (fp->dsect != sect) { 将文件当前扇区的内容读入文件的文件信息结构体的缓冲区内,并更新数据扇区号。
if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
ABORT(fp->fs, FR_DISK_ERR);
}
fp->dsect = sect;
fp->csect++; 调整当前相对扇区号指向下一个扇区。
rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); 这就是每次实际读取的数目。
if (rcnt > btr) rcnt = btr; 当小于512字节时,强制等于用户规定的字节数。
mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); 执行这句以后将rcnt大小的字节从文件扇区缓冲拷贝到用户缓冲区。拷贝位置是从文件指针相对应的地方开始。
rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt;这句话执行一遍,文件指针已经指向500,btr已经等于0,函数接下来就会跳出循环。
第一次读文件执行完成后,主要改变了三个参数:文件指针的位置(指向500)、文件的当前扇区号(1号)、文件的数据扇区号(指向刚刚读入的扇区)。
l 在上一次的基础上再次执行f_read(&FileInf,(void *)FileBuf,500,&ByteRead);
for ( ; btr; rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
if ((fp->fptr % SS(fp->fs)) == 0) { 第二次第一轮读文件时,指针指向500
} 这段程序就不会被执行。
rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); 这是第二次实际读取数目,12字节。
if (rcnt > btr) rcnt = btr; 当需读小于一个扇区剩余字节时,强制等于用户规定的字节数。
mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); 执行这句以后将rcnt大小的字节从文件扇区缓冲拷贝到用户缓冲区。拷贝位置是从文件指针相对应的地方开始。
rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt;这句话执行一遍,文件指针已经指向512,btr已经等于488(512减去刚刚读的12字节)函数接下来重新执行。
if ((fp->fptr % SS(fp->fs)) == 0) { 第二次第二轮读文件时,指针指向512
} 这段程序又被执行。
如果当前扇区没有超出当前簇的范围,if (fp->csect >= fp->fs->csize) {}这段程序不会执行。
sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
sect += fp->csect; //获取下一扇区的绝对扇区号
cc = btr / SS(fp->fs);
if (fp->dsect != sect) { /* 数据扇区不是当前扇区 */
if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK) 读入当前扇区数据 ABORT(fp->fs, FR_DISK_ERR); }
fp->dsect = sect; //数据扇区号更新
fp->csect++; //当前扇区号更新。
rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* 读入的实际数=512-0=512 */
if (rcnt > btr) rcnt = btr; 由于只要求读488个字节,故实际读入数修改。
l 修改参数,再次执行f_read(&FileInf,(void *)FileBuf,800,&ByteRead);
读入500字节后,文件指针的位置(指向500)、文件的当前扇区号(1号)、文件的数据扇区号(绝对扇区号,相对为0)。如果再读800字节,实际跨度为0-2共3个扇区。
在调试的过程中,出了一个较大的问题,由于我刚开始定义的FileBuf只有512字节,现在要读取800字节,结果把很多有用的数据都覆盖了,这就是指针带来的缓冲区溢出问题吧。
文章评论(0条评论)
登录后参与讨论