代码改变世界

FATFS 初学之 f_read/ f_write

2014-08-13 13:09  Danhuise  阅读(12649)  评论(0编辑  收藏  举报

f_read:

 1 /*-----------------------------------------------------------------------*/
 2 /* Read File                                                             */
 3 /*-----------------------------------------------------------------------*/
 4 
 5 FRESULT f_read (
 6     FIL *fp,         /* Pointer to the file object */
 7     void *buff,        /* Pointer to data buffer */
 8     UINT btr,        /* Number of bytes to read */
 9     UINT *br        /* Pointer to number of bytes read */
10 )
11 {
12     FRESULT res;
13     DWORD clst, sect, remain;
14     UINT rcnt, cc;
15     BYTE csect, *rbuff = buff;
16 
17 
18     *br = 0;    /* Initialize byte counter */
19 
20     res = validate(fp->fs, fp->id);                /* Check validity */
21     if (res != FR_OK) LEAVE_FF(fp->fs, res);
22     if (fp->flag & FA__ERROR)                    /* Aborted file? */
23         LEAVE_FF(fp->fs, FR_INT_ERR);
24     if (!(fp->flag & FA_READ))                     /* Check access mode */
25         LEAVE_FF(fp->fs, FR_DENIED);
26     remain = fp->fsize - fp->fptr;
27     if (btr > remain) btr = (UINT)remain;        /* Truncate btr by remaining bytes */
28 
29     for ( ;  btr;                                /* Repeat until all data read */
30         rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
31         if ((fp->fptr % SS(fp->fs)) == 0) {        /* On the sector boundary? */
32             csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
33             if (!csect) {                        /* On the cluster boundary? */
34                 if (fp->fptr == 0) {            /* On the top of the file? */
35                     clst = fp->sclust;            /* Follow from the origin */
36                 } else {                        /* Middle or end of the file */
37 #if _USE_FASTSEEK
38                     if (fp->cltbl)
39                         clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */
40                     else
41 #endif
42                         clst = get_fat(fp->fs, fp->clust);    /* Follow cluster chain on the FAT */
43                 }
44                 if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
45                 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
46                 fp->clust = clst;                /* Update current cluster */
47             }
48             sect = clust2sect(fp->fs, fp->clust);    /* Get current sector */
49             if (!sect) ABORT(fp->fs, FR_INT_ERR);
50             sect += csect;
51             cc = btr / SS(fp->fs);                /* When remaining bytes >= sector size, */
52             if (cc) {                            /* Read maximum contiguous sectors directly */
53                 if (csect + cc > fp->fs->csize)    /* Clip at cluster boundary */
54                     cc = fp->fs->csize - csect;
55                 if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
56                     ABORT(fp->fs, FR_DISK_ERR);
57 #if !_FS_READONLY && _FS_MINIMIZE <= 2            /* Replace one of the read sectors with cached data if it contains a dirty sector */
58 #if _FS_TINY
59                 if (fp->fs->wflag && fp->fs->winsect - sect < cc)
60                     mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
61 #else
62                 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
63                     mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
64 #endif
65 #endif
66                 rcnt = SS(fp->fs) * cc;            /* Number of bytes transferred */
67                 continue;
68             }
69 #if !_FS_TINY
70             if (fp->dsect != sect) {            /* Load data sector if not in cache */
71 #if !_FS_READONLY
72                 if (fp->flag & FA__DIRTY) {        /* Write-back dirty sector cache */
73                     if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
74                         ABORT(fp->fs, FR_DISK_ERR);
75                     fp->flag &= ~FA__DIRTY;
76                 }
77 #endif
78                 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)    /* Fill sector cache */
79                     ABORT(fp->fs, FR_DISK_ERR);
80             }
81 #endif
82             fp->dsect = sect;
83         }
84         rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Get partial sector data from sector buffer */
85         if (rcnt > btr) rcnt = btr;
86 #if _FS_TINY
87         if (move_window(fp->fs, fp->dsect))        /* Move sector window */
88             ABORT(fp->fs, FR_DISK_ERR);
89         mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt);    /* Pick partial sector */
90 #else
91         mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt);    /* Pick partial sector */
92 #endif
93     }
94 
95     LEAVE_FF(fp->fs, FR_OK);
96 }
View Code

函数功能:从已打开的文件中读取数据。

描述:文件对象中的读/写指针以已读取字节数增加。该函数成功后,应该检查 *ByteRead 来检测文件是否结束。在读操作过程中,一旦 *ByteRead < ByteToRead ,则读/写指针到达了文件结束位置。

 

f_write:

  1 /*-----------------------------------------------------------------------*/
  2 /* Write File                                                            */
  3 /*-----------------------------------------------------------------------*/
  4 
  5 FRESULT f_write (
  6     FIL *fp,            /* Pointer to the file object */
  7     const void *buff,    /* Pointer to the data to be written */
  8     UINT btw,            /* Number of bytes to write */
  9     UINT *bw            /* Pointer to number of bytes written */
 10 )
 11 {
 12     FRESULT res;
 13     DWORD clst, sect;
 14     UINT wcnt, cc;
 15     const BYTE *wbuff = buff;
 16     BYTE csect;
 17 
 18 
 19     *bw = 0;    /* Initialize byte counter */
 20 
 21     res = validate(fp->fs, fp->id);            /* Check validity */
 22     if (res != FR_OK) LEAVE_FF(fp->fs, res);
 23     if (fp->flag & FA__ERROR)                /* Aborted file? */
 24         LEAVE_FF(fp->fs, FR_INT_ERR);
 25     if (!(fp->flag & FA_WRITE))                /* Check access mode */
 26         LEAVE_FF(fp->fs, FR_DENIED);
 27     if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0;    /* File size cannot reach 4GB */
 28 
 29     for ( ;  btw;                            /* Repeat until all data written */
 30         wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
 31         if ((fp->fptr % SS(fp->fs)) == 0) {    /* On the sector boundary? */
 32             csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
 33             if (!csect) {                    /* On the cluster boundary? */
 34                 if (fp->fptr == 0) {        /* On the top of the file? */
 35                     clst = fp->sclust;        /* Follow from the origin */
 36                     if (clst == 0)            /* When no cluster is allocated, */
 37                         fp->sclust = clst = create_chain(fp->fs, 0);    /* Create a new cluster chain */
 38                 } else {                    /* Middle or end of the file */
 39 #if _USE_FASTSEEK
 40                     if (fp->cltbl)
 41                         clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */
 42                     else
 43 #endif
 44                         clst = create_chain(fp->fs, fp->clust);    /* Follow or stretch cluster chain on the FAT */
 45                 }
 46                 if (clst == 0) break;        /* Could not allocate a new cluster (disk full) */
 47                 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
 48                 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
 49                 fp->clust = clst;            /* Update current cluster */
 50             }
 51 #if _FS_TINY
 52             if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0))    /* Write-back sector cache */
 53                 ABORT(fp->fs, FR_DISK_ERR);
 54 #else
 55             if (fp->flag & FA__DIRTY) {        /* Write-back sector cache */
 56                 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
 57                     ABORT(fp->fs, FR_DISK_ERR);
 58                 fp->flag &= ~FA__DIRTY;
 59             }
 60 #endif
 61             sect = clust2sect(fp->fs, fp->clust);    /* Get current sector */
 62             if (!sect) ABORT(fp->fs, FR_INT_ERR);
 63             sect += csect;
 64             cc = btw / SS(fp->fs);            /* When remaining bytes >= sector size, */
 65             if (cc) {                        /* Write maximum contiguous sectors directly */
 66                 if (csect + cc > fp->fs->csize)    /* Clip at cluster boundary */
 67                     cc = fp->fs->csize - csect;
 68                 if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
 69                     ABORT(fp->fs, FR_DISK_ERR);
 70 #if _FS_TINY
 71                 if (fp->fs->winsect - sect < cc) {    /* Refill sector cache if it gets invalidated by the direct write */
 72                     mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
 73                     fp->fs->wflag = 0;
 74                 }
 75 #else
 76                 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
 77                     mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
 78                     fp->flag &= ~FA__DIRTY;
 79                 }
 80 #endif
 81                 wcnt = SS(fp->fs) * cc;        /* Number of bytes transferred */
 82                 continue;
 83             }
 84 #if _FS_TINY
 85             if (fp->fptr >= fp->fsize) {    /* Avoid silly cache filling at growing edge */
 86                 if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
 87                 fp->fs->winsect = sect;
 88             }
 89 #else
 90             if (fp->dsect != sect) {        /* Fill sector cache with file data */
 91                 if (fp->fptr < fp->fsize &&
 92                     disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
 93                         ABORT(fp->fs, FR_DISK_ERR);
 94             }
 95 #endif
 96             fp->dsect = sect;
 97         }
 98         wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
 99         if (wcnt > btw) wcnt = btw;
100 #if _FS_TINY
101         if (move_window(fp->fs, fp->dsect))    /* Move sector window */
102             ABORT(fp->fs, FR_DISK_ERR);
103         mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt);    /* Fit partial sector */
104         fp->fs->wflag = 1;
105 #else
106         mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt);    /* Fit partial sector */
107         fp->flag |= FA__DIRTY;
108 #endif
109     }
110 
111     if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;    /* Update file size if needed */
112     fp->flag |= FA__WRITTEN;                        /* Set file change flag */
113 
114     LEAVE_FF(fp->fs, FR_OK);
115 }
View Code

函数功能:向已打开的问价中写入数据。

描述:文件对象中的读/写指针以已写入字节数增加。该函数成功后,应该检查 *ByteWritten 来检测磁盘是否满。在写操作过程中,一旦 *ByteWritten < *ByteToWritten ,则意味着该卷已满。

 

这两个函数在调用过程中会将文件读写指针 fp->fptr的值累加,使得下次再次对该文件操作时从上次操作的断点处继续向下操作。

例:

 1 void main (void)
 2 {
 3     FATFS fs[2];         /* 逻辑驱动器的工作区(文件系统对象) */
 4     FIL fsrc, fdst;      /* 文件对象 */
 5     BYTE buffer[4096];   /* 文件拷贝缓冲区 */
 6     FRESULT res;         /* FatFs 函数公共结果代码 */
 7     UINT br, bw;         /* 文件读/写字节计数 */
 8     
 9     /* 为逻辑驱动器注册工作区 */
10     f_mount(0, &fs[0]);
11     f_mount(1, &fs[1]);
12     
13     /* 打开驱动器 1 上的源文件 */
14     res = f_open(&fsrc, "1:srcfile.dat", FA_OPEN_EXISTING | FA_READ);
15     if (res) die(res);
16     
17     /* 在驱动器 0 上创建目标文件 */
18     res = f_open(&fdst, "0:dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE);
19     if (res) die(res);
20     
21     /* 拷贝源文件到目标文件 */
22     for (;;) {
23         res = f_read(&fsrc, buffer, sizeof(buffer), &br);
24         if (res || br == 0) break;   /* 文件结束错误 */
25         res = f_write(&fdst, buffer, br, &bw);
26         if (res || bw < br) break;   /* 磁盘满错误 */
27     }
28     
29     /* 关闭打开的文件 */
30     f_close(&fsrc);
31     f_close(&fdst);
32     
33     /* 注销工作区(在废弃前) */
34     f_mount(0, NULL);
35     f_mount(1, NULL);
36 }
View Code