一、文件系统

负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。即在磁盘上组织文件的方法。
常用的文件系统:

  • FAT / FATFS
  • NTFS: 基于安全性的文件系统,是Windows NT所采用的独特的文件系统结构
  • CDFS:CDFS是大部分的光盘的文件系统
  • exFAT

FATFS文件系统
FATFS是一个完全免费开源的FAT 文件系统模块,专门为小型的嵌入式系统而设计。完全用标准C 语言编写,所以具有良好的硬件平台独立性。可以移植到8051、PIC、AVR、SH、Z80、H8、ARM 等系列单片机上而只需做简单的修改。它支持FATl2、FATl6 和FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8 位单片机和16 位单片机做了优化。
FATFS文件系统特点

  • Windows兼容的FAT文件系统(支持FAT12/FAT16/FAT32)
  • 与平台无关,移植简单。全C语言编写。
  • 代码量少、效率高。
  • 多种配置选项
    支持多卷(物理驱动器或分区,最多10个卷)
    多个ANSI/OEM代码页包括DBCS
    支持长文件名、ANSI/OEM或Unicode
    支持RTOS
    支持多种扇区大小
    只读、最小化的API和I/O缓冲区等

二、FATFS模块层次结构


①、底层接口,包括存储媒介读/写接口(disk I/O)和供给文件创建修改时间的实时时钟,需要我们根据平台和存储介质编写移植代码。
②、中间层FATFS模块,实现了FAT 文件读/写协议。FATFS模块提供的是ff.c和ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。
③、最顶层是应用层,使用者无需理会FATFS的内部结构和复杂的FAT 协议,只需要调用FATFS模块提供给用户的一系列应用接口函数,如f_open,f_read,f_write 和f_close等,就可以像在PC 上读/写文件那样简单。

三、FATFS文件系统包

FATFS文件系统包下载地址
http://elm-chan.org/fsw/ff/00index_e.html
该网站含有FATFS文件包,也有相应函数的介绍和示范。
FATFS文件系统包结构

  • diskio.c和diskio.h是硬件层。
  • ff.c和ff.h是FATFS的文件系统层和文件系统的API层。
    FATFS模块在移植的时候,一般只需要修改2个文件,即ffconf.h和diskio.c。FATFS模块的所有配置项都是存放在ffconf.h里面,可以通过配置里面的一些选项,来满足自己的需求。diskio.c是硬件层,负责与底层硬件接口适配。

四、FATFS文件系统移植

1、ffconf.h:FATFS关键配置文件

  • _FS_TINY。这个选项在R0.07版本中开始出现,之前的版本都是以独立的C文件出现(FATFS和Tiny FATFS),有了这个选项之后,两者整合在一起了,使用起来更方便。使用FATFS,所以把这个选项定义为0即可。
  • _FS_READONLY。这个用来配置是不是只读,需要读写都用,所以这里设置为0即可。
  • _USE_STRFUNC。这个用来设置是否支持字符串类操作,比如f_putc,f_puts等,需要用到,故设置这里为1。
  • _USE_MKFS。这个用来定时是否使能格式化,需要用到,所以设置这里为1。
  • _USE_FASTSEEK。这个用来使能快速定位,我们设置为1,使能快速定位。
  • _USE_LABEL。这个用来设置是否支持磁盘盘符(磁盘名字)读取与设置。我们设置为1,使能,就可以通过相关函数来读取和设置磁盘的名字了。
  • _CODE_PAGE。这个用于设置语言类型,包括很多选项(见FATFS官网说明),这里设置为936,即简体中文(GBK码,需要c936.c文件支持,该文件在option文件夹)。
  • _USE_LFN。该选项用于设置是否支持长文件名(还需要_CODE_PAGE支持),取值范围为0~3。0,表示不支持长文件名,1 ~ 3是支持长文件名,但是存储地方不一样,我们选择使用3,通过ff_memalloc函数来动态分配长文件名的存储区域。
  • _VOLUMES。用于设置FATFS支持的逻辑设备数目,我们设置为3的话,即支持3个设备(磁盘)。
  • _MAX_SS。扇区缓冲的最大值,一般设置为512。

五、FATFS移植步骤

1、数据类型:在integer.h 里面去定义好数据的类型。这里需要了解你用的编译器的数据类型,并根据编译器定义好数据类型。
2、配置:通过ffconf.h配置FATFS的相关功能,以满足你的需要。
3、函数编写:打开diskio.c,进行底层驱动编写,一般需要编写6 个接口函数


①、disk_initialize函数

② 、disk_status函数


③、 disk_read函数

④ 、disk_write函数

⑤ 、disk_ioctl函数

⑥ 、get_fattime函数

六、FATFS开放函数

f_mount - 注册/注销一个工作区域(Work Area)
f_open - 打开/创建一个文件
f_close - 关闭一个文件
f_read - 读文件
f_write - 写文件
f_lseek - 移动文件读/写指针
f_truncate -截断文件
f_sync -  冲洗缓冲数据 Flush Cached Data
f_forward - 直接转移文件数据到一个数据流
f_stat - 获取文件状态
f_opendir - 打开一个目录
f_closedir -关闭一个已经打开的目录
f_readdir - 读取目录条目
f_mkdir - 创建一个目录
f_unlink -删除一个文件或目录
f_chmod -  改变属性(Attribute)
f_utime -改变时间戳(Timestamp)
f_rename - 重命名/移动一个文件或文件夹
f_chdir - 改变当前目录
f_chdrive - 改变当前驱动器
f_getcwd -  获取当前工作目录
f_getfree - 获取空闲簇 Get Free Clusters
f_getlabel - Get volume label
f_setlabel - Set volume label
f_mkfs - 在驱动器上创建一个文件系统
f_fdisk - Divide a physical drive
f_gets - 读一个字符串
f_putc - 写一个字符
f_puts - 写一个字符串
f_printf - 写一个格式化的字符串
f_tell - 获取当前读/写指针
f_eof - 测试文件结束
f_size - 获取文件大小
f_error - 测试文件上的错误

七、diskio.c代码展示
其中SD卡函数详情看上一讲

#include "diskio.h"        /* FatFs lower layer API */
#include "sdio_sdcard.h"
#include "w25qxx.h"
#include "malloc.h"       //   #define SD_CARD     0  //SD卡,卷标为0
#define EX_FLASH 1  //外部flash,卷标为1#define FLASH_SECTOR_SIZE     512
//对于W25Q128
//前12M字节给fatfs用,12M字节后,用于存放字库,字库占用3.09M.    剩余部分,给客户自己用
u16     FLASH_SECTOR_COUNT=2048*12;    //W25Q1218,前12M字节给FATFS占用
#define FLASH_BLOCK_SIZE    8       //每个BLOCK有8个扇区//初始化磁盘
DSTATUS disk_initialize (BYTE pdrv              /* Physical drive nmuber (0..) */
)
{u8 res=0;     switch(pdrv){case SD_CARD://SD卡res=SD_Init();//SD卡初始化 break;case EX_FLASH://外部flashW25QXX_Init();FLASH_SECTOR_COUNT=2048*12;//W25Q1218,前12M字节给FATFS占用 break;default:res=1; }      if(res)return  STA_NOINIT;else return 0; //初始化成功
}  //获得磁盘状态
DSTATUS disk_status (BYTE pdrv      /* Physical drive nmuber (0..) */
)
{ return 0;
} //读扇区
//drv:磁盘编号0~9
//*buff:数据接收缓冲首地址
//sector:扇区地址
//count:需要读取的扇区数
DRESULT disk_read (BYTE pdrv,       /* Physical drive nmuber (0..) */BYTE *buff,        /* Data buffer to store read data */DWORD sector,   /* Sector address (LBA) */UINT count        /* Number of sectors to read (1..128) */
)
{u8 res=0; if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误            switch(pdrv){case SD_CARD://SD卡res=SD_ReadDisk(buff,sector,count);     while(res)//读出错{SD_Init(); //重新初始化SD卡res=SD_ReadDisk(buff,sector,count);  //printf("sd rd error:%d\r\n",res);}break;case EX_FLASH://外部flashfor(;count>0;count--){W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);sector++;buff+=FLASH_SECTOR_SIZE;}res=0;break;default:res=1; }//处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值if(res==0x00)return RES_OK;  else return RES_ERROR;
}//写扇区
//drv:磁盘编号0~9
//*buff:发送数据首地址
//sector:扇区地址
//count:需要写入的扇区数
#if _USE_WRITE
DRESULT disk_write (BYTE pdrv,          /* Physical drive nmuber (0..) */const BYTE *buff,  /* Data to be written */DWORD sector,       /* Sector address (LBA) */UINT count            /* Number of sectors to write (1..128) */
)
{u8 res=0;  if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误           switch(pdrv){case SD_CARD://SD卡res=SD_WriteDisk((u8*)buff,sector,count);while(res)//写出错{SD_Init();    //重新初始化SD卡res=SD_WriteDisk((u8*)buff,sector,count);    //printf("sd wr error:%d\r\n",res);}break;case EX_FLASH://外部flashfor(;count>0;count--){                                            W25QXX_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);sector++;buff+=FLASH_SECTOR_SIZE;}res=0;break;default:res=1; }//处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值if(res == 0x00)return RES_OK;  else return RES_ERROR;
}
#endif//其他表参数的获得//drv:磁盘编号0~9//ctrl:控制代码//*buff:发送/接收缓冲区指针
#if _USE_IOCTL
DRESULT disk_ioctl (BYTE pdrv,      /* Physical drive nmuber (0..) */BYTE cmd,      /* Control code */void *buff        /* Buffer to send/receive control data */
)
{DRESULT res;                                        if(pdrv==SD_CARD)//SD卡{switch(cmd){case CTRL_SYNC:res = RES_OK; break;   case GET_SECTOR_SIZE:*(DWORD*)buff = 512; res = RES_OK;break;     case GET_BLOCK_SIZE:*(WORD*)buff = SDCardInfo.CardBlockSize;res = RES_OK;break;   case GET_SECTOR_COUNT:*(DWORD*)buff = SDCardInfo.CardCapacity/512;res = RES_OK;break;default:res = RES_PARERR;break;}}else if(pdrv==EX_FLASH) //外部FLASH  {switch(cmd){case CTRL_SYNC:res = RES_OK; break;     case GET_SECTOR_SIZE:*(WORD*)buff = FLASH_SECTOR_SIZE;res = RES_OK;break;     case GET_BLOCK_SIZE:*(WORD*)buff = FLASH_BLOCK_SIZE;res = RES_OK;break;   case GET_SECTOR_COUNT:*(DWORD*)buff = FLASH_SECTOR_COUNT;res = RES_OK;break;default:res = RES_PARERR;break;}}else res=RES_ERROR;//其他的不支持return res;
}
#endif
//获得时间
//User defined function to give a current time to fatfs module      */
//31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
//15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
DWORD get_fattime (void)
{                return 0;
}
//动态分配内存
void *ff_memalloc (UINT size)
{return (void*)mymalloc(SRAMIN,size);
}
//释放内存
void ff_memfree (void* mf)
{myfree(SRAMIN,mf);
}

FATFS文件系统详解就讲解到这里啦!!!

FATFS文件系统详解相关推荐

  1. fatfs文件系统详解之f_mkfs函数分析

    前序 前面两篇文章分析了FAT文件系统,没有代码总感觉很空虚寂寞冷,fatfs正好是一个开源专门应对fat文件系统的代码,从这篇文章开始分析fatfs代码,"理论+实践"才是悟道的 ...

  2. fatfs文件系统详解之f_write函数分析

    前序 本篇分析f_write()函数,fatfs文件系统对应的不知道文件的读写,也对应了文件的其他的操作,也有文件夹的操作,函数分析确实是一个非常耗时耗精力的事情,此函数分析完之后,就结束函数分析. ...

  3. fatfs文件系统详解之f_mount函数分析

    前序 上一篇分析了格式化一个磁盘的时候发生了什么,在格式化一个磁盘之后,就要将磁盘进行挂载,"挂载"这个词听起来很抽象,但是在软件代码上,到底发生了什么? 分析假设 (1)假设一个 ...

  4. fatfs文件系统详解之f_read函数分析

    前序 文件系统的最终目的是为了进行文件的管理,文件的管理就是读写.删除等操作,文件打开后,本篇继续分析读操作. 分析假设 (1)假设一个磁盘就一个分区. (2)只分析FAT32文件系统相关的代码. ( ...

  5. NTFS文件系统详解(三)NTFS元文件解析

    NTFS文件系统详解(三)NTFS元文件解析 一. 分析$Boot文件 二.分析文件记录 1. MFT偏移地址计算 2. 文件记录的结构 3. 属性的属性头分析 4. 属性的属性体分析 NTFS文件系 ...

  6. linux根文件系统配置,Linux学习笔记__ Linux根文件系统详解

    Linux根文件系统详解 文件系统: rootfs:根文件系统 FHS:Linux boot:系统启动相关的文件,如内核.initrd.以及grub(bootloader) /dev: 设备文件 块 ...

  7. NTFS文件系统详解(二)MBR\EBR基本信息

    NTFS文件系统详解(二)MBR\EBR基本信息 一.MBR结构分析 1. 第一个分区表项 2. 第二个分区表项 3. 第三个分区表项 4. 第四个分区表项 二.EBR结构分析 1. 第一个分区表项 ...

  8. NTFS文件系统详解(一)硬盘基本信息

    NTFS文件系统详解(一)硬盘基本信息 一.硬盘的内部结构 1. 盘面号 2. 磁道 3. 柱面 4. 扇区 二.硬盘的分区结构 NTFS文件系统详解系列 一般硬盘正面贴有产品标签,主要包括厂家信息和 ...

  9. [自制操作系统] JOS文件系统详解支持工作路径MSH

    本文分为两部分: 第一部分将详细分析JOS的文件系统及文件描述符的实现方法. 第二部分将实现工作路径,提供新的系统调用,完善用户空间工具. 本文中支持的新特性: 支持进程工作目录 提供getcwd与c ...

最新文章

  1. tensorflow with求导_3.4tensorflow2.x自动求导原理函数详解
  2. 初创互联网公司简明创业指南 - YC新掌门Sam Altman
  3. C++中delete和delete[]的区别
  4. Hyper-v下安装第一台Windows Server 2012 R2
  5. 解析nextTick---vue3任务调度
  6. VC里一些容易混淆的地方(转)
  7. 9. grouped product
  8. poj1113 凸包
  9. kafka 安装步骤
  10. 破解还原卡的方法总结!! - Kevins的天空 - CSDNBlog
  11. Github中的缩写(PR, WIP, PTAL, TBR, TL, LGTM, SGTM, AFAIK, CC)含义
  12. 2019上半年教资综合素质——主观题
  13. easyui实例案例介绍
  14. 信念就是一种观念对不对_信念与观念一字之差天差地别
  15. 解密“达达-京东到家”的订单即时派发技术原理和实践
  16. motion_model总结
  17. vue v-html字体大小修改,详解三种方式解决vue中v-html元素中标签样式
  18. java session时间_java session时长问题,java设置session超时时间实例
  19. 通过yum下载软件包的三种方式
  20. Hexo提交搜索引擎收录-Baidu收录、Google收录

热门文章

  1. 对傅里叶级数和傅里叶变换的理解
  2. android char 几个字节,Android日常基础知识整理(上)
  3. Ruoyi数据库CURD
  4. 关于使用tiledMap加载不出资源问题
  5. miniui自定义messageBox框
  6. 数论:求一个数的因子专题(因子数,因子和,质因子)
  7. H5实现聚合支付及踩坑
  8. mysql数据库应用多选题答案_多项选择题_MySQL数据库技术与应用答案_学小易找答案...
  9. 集创赛备赛:Robei八角板7020简介
  10. Word无法启动转换器mswrd632.wpc”方法