<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
5、f_open()执行完auto_mount()后
下一个函数:
trace_path(&dj, fn, path, &dir); /* Trace the file path */
这个函数里面只有path指向文件路径,其它三个都是未经初始化的指针,应该都是在这个函数里面进行设置。Dj是目录结构体,fn是8.3文件名数组,dir是指向fs扇区缓冲里当前文件目录项的指针。
从函数名称和参数可以推断出它的主要功能是将文件名从路径中提取出来,并转变成从标准8.3格式,同时找到文件所在目录,并将目录扇区读入文件系统缓冲区,依据文件目录项的信息填充dj结构体。
新的<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />007c代码中已经改成了follow_path();
以下是源代码:
FRESULT trace_path ( DIR *dj, char *fn,const char *path, BYTE **dir )
{
dj->fs = fs;
clust = fs->dirbase;
if (fs->fs_type == FS_FAT32) {
dj->clust = dj->sclust = clust; //目录项的当前簇和开始簇都指向根目录区
dj->sect = clust2sect(clust);} //从簇号得到相应的扇区。
dj->index = 0; //目录索引项先初始化为0
for (;;) {
ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */
make_dirfile(&path, fn)功能是获得文件名,跟进源代码看一看:有些地方还不是太清晰,但大概意思是抽取目录。有效格式如:/dir1/dir11/file1.txt等,执行该函数后fn[]应该=“dir1***.***”,性质是目录。
move_window(dj->sect);//这个函数是将对应簇读到文件系统缓冲区。
dptr = &fs->win[(dj->index & 15) * 32]; //这是一个目录项的指针。
memcmp(&dptr[DIR_Name], fn, 8+3); //将文件名或目录名与当前目录项比较,看是不是需要打开的文件或者目录。
如果不是,则取出下一个目录项:next_dir_entry(dj);然后进行循环。没有找到的。外层循环继续把目录剥离,往下寻找。最终找到对应的文件。
trace_path()函数返回以后,f_open()函数主要根据trace_path所得到的信息填充file文件结构体。比如:
fp->dir_sect = dj.fs->winsect; /* 指向目录项所在扇区 */
fp->dir_ptr = dir; //指向扇区中对应目录项的指针
fp->flag = mode; /* File access mode */
fp->org_clust = /* File start cluster */
((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
LD_WORD(&dir[DIR_FstClusLO]);
fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */
fp->fptr = 0; fp->csect = 255; /* 文件读写指针为0 */
fp->fs = dj.fs; fp->id = dj.fs->id; /* Owner file system object of the file */
f_open()到此执行结束。
6、fgets(data, sizeof(data), &file)的执行
该函数的主要参数是数据缓冲区data,和文件结构描述符file。跟进源代码:
while (i < len - 1) { /* Read bytes until buffer gets filled */
f_read(fil, p, 1, &rc);
if (rc != 1) break; /* Break when no data to read */
if (*p == '\r') continue; /* Strip '\r' */
i++;
if (*p++ == '\n') break; /* Break when reached end of line */
}
主要是调用f_read函数,一个字节一个字节的读进来,如果遇到\r\n,则读入结束,正确返回buf缓冲区指针;不正确返回0.
所以读文件的重点在f_read()函数。
7、f_read(fil, p, 1, &rc)函数的分析
读函数中第一个关键语句: remain = fp->fsize - fp->fptr; //文件大小减去当前位置,得到剩下的字节数。if (btr > remain) btr = (UINT)remain;//如果要读的字节数大于剩余字节数,则调整。
举个例子,从文件头开始读5128个字节,共占据11个扇区。一簇以8个扇区计算。
for ( ; btr; /* Repeat until all data transferred */
rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt)
{
if ((fp->fptr % 512U) == 0) { /*读初始指针位于扇区位于边界 */
sect = clust2sect(fp->curr_clust) + fp->csect; /* 簇的第一个扇区 */
cc = btr / 512U; /* cc="10"表示多于一个扇区, */
if (cc) { /* Read maximum contiguous sectors directly */
if (fp->csect + cc > fp->fs->csize) /* 多于一个簇 */
cc = fp->fs->csize - fp->csect; //暂时先读一个簇。
if (disk_read(0, rbuff, sect, (BYTE)cc) != RES_OK)
goto fr_error;
fp->csect += (BYTE)cc; /* 移动到下一个簇 */
rcnt = 512U * cc; /* Number of bytes transferred */
continue;
第二次读时,要执行下面语句:第二次要读两个扇区
if (fp->csect >= fp->fs->csize) { /* 移动到下一簇 */
clust = (fp->fptr == 0) ? /* On the top of the file? */
fp->org_clust : get_cluster(fp->curr_clust);
if (clust < 2 || clust >= fp->fs->max_clust) goto fr_error;
fp->curr_clust = clust; /*更新当前簇 */
fp->csect = 0; /* 簇内扇区号变为0 */
}
第二次读时额外执行的语句。
}
fp->csect++; /* 这个在第三次读时也会执行 */
}//往下语句也会在第三次读时执行。
sect = clust2sect(fp->curr_clust) + fp->csect - 1; /* 如果文件读写指针不在扇区边界,为了读到数据,必须往前走一个扇区 */
if (!move_window(sect)) goto fr_error; /* Move sector window */
rcnt = 512U - (fp->fptr % 512U); * Get partial sector from sector window */
if (rcnt > btr) rcnt = btr;
memcpy(rbuff, &fp->fs->win[fp->fptr % 512U], rcnt);
}
8、f_close()
主要做了两个工作:(1)res = f_sync(fp);将文件的改动写入,同时调用函数sync()将文件系统变化写入文件系统相应信息区域。(2)fp->fs=0,将文件关闭。
文章评论(0条评论)
登录后参与讨论