当前位置: 首页> 健康> 美食 > 青岛创世网络网站建设_网页设计与制作试卷分析报告_网络营销策划模板_sem竞价培训班

青岛创世网络网站建设_网页设计与制作试卷分析报告_网络营销策划模板_sem竞价培训班

时间:2025/7/14 12:23:17来源:https://blog.csdn.net/stupid24863/article/details/146223213 浏览次数:0次
青岛创世网络网站建设_网页设计与制作试卷分析报告_网络营销策划模板_sem竞价培训班

一:f_write

FRESULT f_write (FIL* fp,			/* Open file to be written */const void* buff,	/* Data to be written */UINT btw,			/* Number of bytes to write */UINT* bw			/* Number of bytes written */
)
{FRESULT res;FATFS *fs;DWORD clst;LBA_t sect;UINT wcnt, cc, csect;const BYTE *wbuff = (const BYTE*)buff;*bw = 0;	/* Clear write byte counter */res = validate(&fp->obj, &fs);			/* Check validity of the file object */if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);	/* Check validity */if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);	/* Check access mode *//* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);}for ( ; btw > 0; btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) {	/* Repeat until all data written */if (fp->fptr % SS(fs) == 0) {		/* On the sector boundary? */csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1);	/* Sector offset in the cluster */if (csect == 0) {				/* On the cluster boundary? */if (fp->fptr == 0) {		/* On the top of the file? */clst = fp->obj.sclust;	/* Follow from the origin */if (clst == 0) {		/* If no cluster is allocated, */clst = create_chain(&fp->obj, 0);	/* create a new cluster chain */}} else {					/* On the middle or end of the file */
#if FF_USE_FASTSEEKif (fp->cltbl) {clst = clmt_clust(fp, fp->fptr);	/* Get cluster# from the CLMT */} else
#endif{clst = create_chain(&fp->obj, fp->clust);	/* Follow or stretch cluster chain on the FAT */}}if (clst == 0) break;		/* Could not allocate a new cluster (disk full) */if (clst == 1) ABORT(fs, FR_INT_ERR);if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);fp->clust = clst;			/* Update current cluster */if (fp->obj.sclust == 0) fp->obj.sclust = clst;	/* Set start cluster if the first write */}
#if FF_FS_TINYif (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);	/* Write-back sector cache */
#elseif (fp->flag & FA_DIRTY) {		/* Write-back sector cache */if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);fp->flag &= (BYTE)~FA_DIRTY;}
#endifsect = clst2sect(fs, fp->clust);	/* Get current sector */if (sect == 0) ABORT(fs, FR_INT_ERR);sect += csect;cc = btw / SS(fs);				/* When remaining bytes >= sector size, */if (cc > 0) {					/* Write maximum contiguous sectors directly */if (csect + cc > fs->csize) {	/* Clip at cluster boundary */cc = fs->csize - csect;}if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
#if FF_FS_MINIMIZE <= 2
#if FF_FS_TINYif (fs->winsect - sect < cc) {	/* Refill sector cache if it gets invalidated by the direct write */memcpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));fs->wflag = 0;}
#elseif (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */memcpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));fp->flag &= (BYTE)~FA_DIRTY;}
#endif
#endifwcnt = SS(fs) * cc;		/* Number of bytes transferred */continue;}
#if FF_FS_TINYif (fp->fptr >= fp->obj.objsize) {	/* Avoid silly cache filling on the growing edge */if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);fs->winsect = sect;}
#elseif (fp->sect != sect && 		/* Fill sector cache with file data */fp->fptr < fp->obj.objsize &&disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {ABORT(fs, FR_DISK_ERR);}
#endiffp->sect = sect;}wcnt = SS(fs) - (UINT)fp->fptr % SS(fs);	/* Number of bytes remains in the sector */if (wcnt > btw) wcnt = btw;					/* Clip it by btw if needed */
#if FF_FS_TINYif (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR);	/* Move sector window */memcpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt);	/* Fit data to the sector */fs->wflag = 1;
#elsememcpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt);	/* Fit data to the sector */fp->flag |= FA_DIRTY;
#endif}fp->flag |= FA_MODIFIED;				/* Set file change flag */LEAVE_FF(fs, FR_OK);
}

1. 函数功能

    f_write 是 FATFS 文件系统库的核心函数,用于 向已打开的文件写入数据。主要功能包括:

  • 数据写入:将用户缓冲区数据写入文件的指定位置。

  • 簇链管理:动态扩展文件簇链(分配新簇),处理大文件和跨簇写入。

  • 缓存优化:利用文件对象缓存或全局窗口缓存优化小块数据写入。

  • 错误处理:检测磁盘错误、簇分配失败、权限问题等。


2. 输入输出

参数类型说明
fpFIL*已打开的文件对象指针,记录文件状态(如当前簇、文件指针等)。
buffconst void*用户提供的待写入数据缓冲区。
btwUINT请求写入的字节数。
bwUINT*实际写入的字节数(输出参数)。
返回值FRESULT操作结果(如 FR_OKFR_DISK_ERRFR_DENIED)。

3. 核心逻辑流程

步骤 1:参数校验与初始化
*bw = 0;                                    // 初始化已写入字节数
res = validate(&fp->obj, &fs);             // 验证文件对象有效性
if (res != FR_OK || ...) LEAVE_FF(...);     // 错误检查
if (!(fp->flag & FA_WRITE)) ...            // 检查写权限
  • 关键点:确保文件对象合法且以写模式打开。


步骤 2:处理文件大小限制(非 exFAT)
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr {btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
}
if (非 exFAT 且文件指针 + btw 溢出) btw = 调整至最大合法值;                 // 避免 4GB 溢出(FAT 限制)
  • FAT 限制:FAT12/16/32 文件大小不超过 4GB(DWORD 上限)。


步骤 3:主循环(按簇/扇区写入)
for (; btw > 0; btw -= wcnt, ...) {// 检查文件指针是否位于扇区边界if (fp->fptr % SS(fs) == 0) {csect = 计算簇内扇区偏移;if (csect == 0) {                   // 位于簇边界,可能需要分配新簇if (fp->fptr == 0) {           // 文件起始,获取初始簇clst = fp->obj.sclust;if (clst == 0) clst = create_chain(...); // 分配新簇链} else {                        // 文件中间或末尾,扩展簇链clst = create_chain(...);   // 从当前簇扩展}fp->clust = clst;               // 更新当前簇}// 处理缓存写回(避免脏数据丢失)
#if FF_FS_TINYsync_window(fs);                    // Tiny模式:同步全局窗口缓存
#elseif (fp->flag & FA_DIRTY)            // 标准模式:写回私有缓存disk_write(fp->buf, fp->sect);
#endifsect = clst2sect(fs, fp->clust) + csect; // 计算物理扇区号// 批量写入连续扇区(优化)if (剩余字节 >= 扇区大小) {disk_write(wbuff, sect, cc);     // 直接写入多个扇区wcnt = SS(fs) * cc;             // 更新已写入字节数continue;}// 加载当前扇区到缓存(若非末尾或需要部分写入)
#if FF_FS_TINYfs->winsect = sect;                 // 更新全局窗口缓存位置
#elsedisk_read(fp->buf, sect);           // 读取扇区到私有缓存
#endiffp->sect = sect;                    // 记录当前扇区}// 写入部分数据到缓存wcnt = 计算当前扇区剩余空间;memcpy(缓存地址, wbuff, wcnt);           // 数据复制到缓存
#if FF_FS_TINYfs->wflag = 1;                          // 标记全局缓存为脏
#elsefp->flag |= FA_DIRTY;                   // 标记私有缓存为脏
#endif
}
  • 关键操作

    • 簇链扩展:通过 create_chain 动态分配簇,维护 FAT 表。

    • 批量写入优化:当剩余数据超过扇区大小时,直接写入连续扇区。

    • 缓存管理:处理脏数据写回,确保数据一致性。


4. 关键设计思想

(1) 簇链动态分配
  • create_chain 函数
    根据当前簇号查找或分配新簇,更新 FAT 表。若当前簇为0(文件未分配簇),则创建新簇链;否则扩展现有簇链。

  • 错误处理

    • clst == 0:磁盘空间不足(FR_DISK_FULL)。

    • clst == 1:内部错误(FR_INT_ERR)。

    • clst == 0xFFFFFFFF:磁盘 I/O 错误(FR_DISK_ERR)。

(2) 写入优化策略
  • 连续扇区批量写入
    当剩余数据量大于等于扇区大小且对齐时,直接调用 disk_write 写入多个扇区,减少 I/O 次数。

  • 缓存复用
    对小数据或非对齐写入,先写入文件对象或全局缓存,延迟写回磁盘,减少碎片化操作。

(3) 缓存一致性
  • 脏数据标记

    • 标准模式:文件对象私有缓存标记为 FA_DIRTY,后续同步时写回。

    • Tiny 模式:全局窗口缓存标记为 fs->wflag = 1,通过 sync_window 写回。

  • 缓存预读
    在部分写入场景下,若目标扇区不在缓存中,需先读取原扇区内容,避免覆盖未修改数据。


5. 条件编译与配置

宏定义功能说明
FF_FS_TINY启用 Tiny 模式,使用全局窗口缓存(fs->win),节省内存但降低并发性能。
FF_USE_FASTSEEK启用快速定位(CLMT),优化大文件随机写入的簇查找。
FF_FS_EXFAT支持 exFAT 文件系统,解除 4GB 文件大小限制,优化簇管理。
FF_FS_READONLY禁用写操作相关代码(如簇分配、缓存写回)。

6. 错误处理机制

错误码触发条件
FR_DISK_ERR磁盘 I/O 错误(如 disk_write 或 disk_read 失败)。
FR_INT_ERR内部逻辑错误(如无效簇号 clst == 1)。
FR_DENIED文件未以写模式打开或写保护。
FR_DISK_FULL磁盘空间不足,无法分配新簇。

7. 示例流程

场景 1:追加写入文件末尾
  1. 簇链检查:当前簇已满,调用 create_chain 分配新簇。

  2. 扇区写入:直接写入新簇的连续扇区,更新文件大小 fp->obj.objsize

  3. 缓存标记:若为部分扇区写入,标记缓存为脏,延迟写回。

场景 2:跨簇写入
  1. 当前簇剩余空间不足:写入部分数据至当前簇末尾。

  2. 分配新簇:调用 create_chain 扩展簇链。

  3. 继续写入:剩余数据写入新簇的扇区,更新 fp->clust 和 fp->sect


8. 总结

特性说明
核心功能动态管理簇链,高效处理不同大小的写入请求,维护文件系统完整性。
性能优化批量连续扇区写入、缓存延迟写回、簇预分配策略。
资源管理按需分配簇,避免空间浪费;缓存机制减少磁盘访问。
错误鲁棒性严格检查磁盘状态、簇有效性,确保写入操作原子性。
可配置性支持多种文件系统(FAT/exFAT)和模式(Tiny/标准),适应不同嵌入式场景。

    通过 f_write 函数,FATFS 实现了高效可靠的文件写入机制,兼顾性能与资源效率,满足嵌入式系统对存储操作的严苛要求。

关键字:青岛创世网络网站建设_网页设计与制作试卷分析报告_网络营销策划模板_sem竞价培训班

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: