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 }
函数功能:从已打开的文件中读取数据。
描述:文件对象中的读/写指针以已读取字节数增加。该函数成功后,应该检查 *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 }
函数功能:向已打开的问价中写入数据。
描述:文件对象中的读/写指针以已写入字节数增加。该函数成功后,应该检查 *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 }