首页 > 代码库 > FATFS 初学之 f_lseek

FATFS 初学之 f_lseek

  1 /*-----------------------------------------------------------------------*/  2 /* Seek File R/W Pointer                                                 */  3 /*-----------------------------------------------------------------------*/  4   5 FRESULT f_lseek (  6     FIL *fp,        /* Pointer to the file object */  7     DWORD ofs        /* File pointer from top of file */  8 )  9 { 10     FRESULT res; 11  12  13     res = validate(fp->fs, fp->id);        /* Check validity of the object */ 14     if (res != FR_OK) LEAVE_FF(fp->fs, res); 15     if (fp->flag & FA__ERROR)            /* Check abort flag */ 16         LEAVE_FF(fp->fs, FR_INT_ERR); 17  18 #if _USE_FASTSEEK 19     if (fp->cltbl) {    /* Fast seek */ 20         DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; 21  22         if (ofs == CREATE_LINKMAP) {    /* Create CLMT */ 23             tbl = fp->cltbl; 24             tlen = *tbl++; ulen = 2;    /* Given table size and required table size */ 25             cl = fp->sclust;            /* Top of the chain */ 26             if (cl) { 27                 do { 28                     /* Get a fragment */ 29                     tcl = cl; ncl = 0; ulen += 2;    /* Top, length and used items */ 30                     do { 31                         pcl = cl; ncl++; 32                         cl = get_fat(fp->fs, cl); 33                         if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); 34                         if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); 35                     } while (cl == pcl + 1); 36                     if (ulen <= tlen) {        /* Store the length and top of the fragment */ 37                         *tbl++ = ncl; *tbl++ = tcl; 38                     } 39                 } while (cl < fp->fs->n_fatent);    /* Repeat until end of chain */ 40             } 41             *fp->cltbl = ulen;    /* Number of items used */ 42             if (ulen <= tlen) 43                 *tbl = 0;        /* Terminate table */ 44             else 45                 res = FR_NOT_ENOUGH_CORE;    /* Given table size is smaller than required */ 46  47         } else {                        /* Fast seek */ 48             if (ofs > fp->fsize)        /* Clip offset at the file size */ 49                 ofs = fp->fsize; 50             fp->fptr = ofs;                /* Set file pointer */ 51             if (ofs) { 52                 fp->clust = clmt_clust(fp, ofs - 1); 53                 dsc = clust2sect(fp->fs, fp->clust); 54                 if (!dsc) ABORT(fp->fs, FR_INT_ERR); 55                 dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); 56                 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) {    /* Refill sector cache if needed */ 57 #if !_FS_TINY 58 #if !_FS_READONLY 59                     if (fp->flag & FA__DIRTY) {        /* Write-back dirty sector cache */ 60                         if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) 61                             ABORT(fp->fs, FR_DISK_ERR); 62                         fp->flag &= ~FA__DIRTY; 63                     } 64 #endif 65                     if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK)    /* Load current sector */ 66                         ABORT(fp->fs, FR_DISK_ERR); 67 #endif 68                     fp->dsect = dsc; 69                 } 70             } 71         } 72     } else 73 #endif 74  75     /* Normal Seek */ 76     { 77         DWORD clst, bcs, nsect, ifptr; 78  79         if (ofs > fp->fsize                    /* In read-only mode, clip offset with the file size */ 80 #if !_FS_READONLY 81              && !(fp->flag & FA_WRITE) 82 #endif 83             ) ofs = fp->fsize; 84  85         ifptr = fp->fptr; 86         fp->fptr = nsect = 0; 87         if (ofs) { 88             bcs = (DWORD)fp->fs->csize * SS(fp->fs);    /* Cluster size (byte) */ 89             if (ifptr > 0 && 90                 (ofs - 1) / bcs >= (ifptr - 1) / bcs) {    /* When seek to same or following cluster, */ 91                 fp->fptr = (ifptr - 1) & ~(bcs - 1);    /* start from the current cluster */ 92                 ofs -= fp->fptr; 93                 clst = fp->clust; 94             } else {                                    /* When seek to back cluster, */ 95                 clst = fp->sclust;                        /* start from the first cluster */ 96 #if !_FS_READONLY 97                 if (clst == 0) {                        /* If no cluster chain, create a new chain */ 98                     clst = create_chain(fp->fs, 0); 99                     if (clst == 1) ABORT(fp->fs, FR_INT_ERR);100                     if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);101                     fp->sclust = clst;102                 }103 #endif104                 fp->clust = clst;105             }106             if (clst != 0) {107                 while (ofs > bcs) {                        /* Cluster following loop */108 #if !_FS_READONLY109                     if (fp->flag & FA_WRITE) {            /* Check if in write mode or not */110                         clst = create_chain(fp->fs, clst);    /* Force stretch if in write mode */111                         if (clst == 0) {                /* When disk gets full, clip file size */112                             ofs = bcs; break;113                         }114                     } else115 #endif116                         clst = get_fat(fp->fs, clst);    /* Follow cluster chain if not in write mode */117                     if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);118                     if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);119                     fp->clust = clst;120                     fp->fptr += bcs;121                     ofs -= bcs;122                 }123                 fp->fptr += ofs;124                 if (ofs % SS(fp->fs)) {125                     nsect = clust2sect(fp->fs, clst);    /* Current sector */126                     if (!nsect) ABORT(fp->fs, FR_INT_ERR);127                     nsect += ofs / SS(fp->fs);128                 }129             }130         }131         if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {    /* Fill sector cache if needed */132 #if !_FS_TINY133 #if !_FS_READONLY134             if (fp->flag & FA__DIRTY) {            /* Write-back dirty sector cache */135                 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)136                     ABORT(fp->fs, FR_DISK_ERR);137                 fp->flag &= ~FA__DIRTY;138             }139 #endif140             if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)    /* Fill sector cache */141                 ABORT(fp->fs, FR_DISK_ERR);142 #endif143             fp->dsect = nsect;144         }145 #if !_FS_READONLY146         if (fp->fptr > fp->fsize) {            /* Set file change flag if the file size is extended */147             fp->fsize = fp->fptr;148             fp->flag |= FA__WRITTEN;149         }150 #endif151     }152 153     LEAVE_FF(fp->fs, res);154 }
View Code

函数功能:移动一个打开的文件对象的文件读/写指针。也可以被用来扩展文件大小(簇预分配)。

描述:

f_lseek函数当FS_MINIMIZE <= 2时可用。
offset只能被指定为相对于文件起始处的字节数。当在写模式下指定了一个超过文件大小的offset时,文件的大小将被扩展,并且该扩展的区域中的数据是未定义的。这适用于为快速写操作迅速地创建一个大的文件。
f_lseek函数成功后,为了确保读/写指针已被正确地移动,必须检查文件对象中的成员fptr。如果fptr不是所期望的值,则发生了下列情况之一。
文件结束。指定的offset被钳在文件大小,因为文件已被以只读模式打开。
磁盘满。卷上没有足够的空闲空间去扩展文件大小。

 

例:

 1     /* 移动文件读/写指针到相对于文件起始处偏移为5000字节处 */ 2     res = f_lseek(file, 5000); 3      4     /* 移动文件读/写指针到文件结束处,以便添加数据 */ 5     res = f_lseek(file, file->fsize); 6      7     /* 向前3000字节 */ 8     res = f_lseek(file, file->fptr + 3000); 9     10     /* 向后(倒带)2000字节(注意溢出) */11     res = f_lseek(file, file->fptr - 2000);12     13     /* 簇预分配(为了防止在流写时缓冲区上溢 */14     res = f_open(file, recfile, FA_CREATE_NEW | FA_WRITE); /* 创建一个文件 */15     16     res = f_lseek(file, PRE_SIZE);         /* 预分配簇 */17     if (res || file->fptr != PRE_SIZE) ... /* 检查文件大小是否已被正确扩展 */18     19     res = f_lseek(file, DATA_START);       /* 没有簇分配延迟地记录数据流 */20     ...21     22     res = f_truncate(file);                /* 截断未使用的区域 */23     res = f_lseek(file, 0);                /* 移动到文件起始处 */24     ...25     26     res = f_close(file);27     
View Code