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 #endif
104                 fp->clust = clst;
105             }
106             if (clst != 0) {
107                 while (ofs > bcs) {                        /* Cluster following loop */
108 #if !_FS_READONLY
109                     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                     } else
115 #endif
116                         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_TINY
133 #if !_FS_READONLY
134             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 #endif
140             if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)    /* Fill sector cache */
141                 ABORT(fp->fs, FR_DISK_ERR);
142 #endif
143             fp->dsect = nsect;
144         }
145 #if !_FS_READONLY
146         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 #endif
151     }
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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM