首页 > 编程知识 正文

fatfs文件系统工作原理,熟知评卷规则

时间:2023-05-06 08:02:23 阅读:172553 作者:539

上一篇文章中写的部分内容来自FatFs的官方文档,但添加了几个额外的章节和内容。 不是原始FatFs官方文档的翻译。 要关注与FatFs的官方文档,请参阅本文的参考章节。

路径名格式FatFs中的路径名格式与DOS/Windows文件名规范[drive#:][/]directory/file类似。 FatFs支持长文件名(LFN )和8.3格式的文件名(SFN )。 如果FF_USE_LFN=1,则可以使用LFN。 与DOS/Windows API方法类似,FatFs的子目录也用或/分隔。 自动跳过和忽略重复的分隔符。 唯一的区别在于指定逻辑驱动器的驱动器前缀为数字+冒号格式。 如果省略驱动器前缀,则驱动器盘符将被视为默认驱动器(驱动器0或当前驱动器)。 例如0:/folder/myfile.exe。

控制字符到x1F (识别为路径名的末尾。 路径名的开头或嵌入的空格在LFN配置中作为名称的一部分是有效的,但在非LFN配置中,空格被识别为路径名的末尾。 在这两种配置中,后续的空格和点都将被忽略。

缺省配置(FF_FS_RPATH==0)不包含当前目录的概念,如面向操作系统的文件系统。 卷上的每个对象始终由从根目录开始的完整路径名指定。 不能使用点目录名“.”或“…”。 标题分隔符被忽略,可以存在也可以省略。 默认驱动器固定为驱动器0。

如果启用相对路径(FF_FS_RPATH=1),则会遵循从根目录指定的路径(如果存在标题分隔符)。 如果没有,则从f_chdir函数设置的驱动器的当前目录进行跟随。 路径名也可以使用点名称。 默认驱动器是f_chdrive功能设置的当前驱动器。

pathname ff _ fs _ rpath==0ff _ fs _ rpath=1file.txt驱动器0根目录中的文件当前驱动器当前目录中的文件/file.txt驱动器0根目录中的文件当前驱动器根目录中的文件驱动器0的当前目录/驱动器0的当前驱动器的根目录2:驱动器2的根目录2: 驱动器2的根目录驱动器2的根目录2:file.txt驱动器2的根目录中的文件驱动器2当前目录中的文件…/file.txt无效名称父目录中的文件.此目录的名称无效.当前目录的父目录(* ) dir1/… .当前目录的名称无效.根目录的名称无效(始终为无效) 如果FF_STR_VOLUME_ID==1选项,则可以使用任何字符串卷ID作为驱动器前缀。 例如," flash:file1.txt "、" ram:temp.dat "或" sd:"。 如果FF_STR_VOLUME_ID==2,则可以使用Unix样式的驱动器前缀。 例如,/flash/file1.txt、/ram/temp.dat或/usb。 但是,无法遍历驱动器,如“/flash/…/ram/temp.dat”。 Unix样式的驱动器前缀可能会混淆卷ID和文件名之间的标识符。 例如,“/flash”是什么意思? 根目录文件“flash”是否有驱动器前缀,或者驱动器前缀是否为“flash”? 如果标题斜线后的字符串与卷ID匹配,则视为驱动器前缀。

注意:在此版本中,二进制名称“…”不能跟随exFAT卷的父目录。 作为“.”工作。 在那里。

8.3格式文件名8.3格式文件名或短文件名(Short File Name,SFN )是DOS FAT12/FAT16时代的命名方法,如下图所示。

3358www.Sina.com/意味着文件名或目录名的主体部分不超过8个字节,目录名没有扩展名。 文件名可以附加表示文件类型3358www.Sina.com/分隔符的扩展名,将文件名与扩展名分开,根据8.3格式的命名规则,所谓3358www.Sina.com/是指文件名的扩展名部分DOS的默认做法是将多余的字符替换为~ x。 其中,x是数字,例如是123456~8.TXT。 此外,如果文件没有扩展名,则后面的点没有意义。 也就是说,文件和文件.是同一个文件。

FAT文件本身不区分大小写,但大多数系统将名称统一转换为大写,FatFs也是如此!

长文件名长文件名(Long File Name,LFN )、文件的基本文件名(不含扩展名)或扩展名超过3个字节的文件名称为长文件名。

有效区分大小写在FAT文件系统上,对象名称(文件/目录名称)的有效字符为0-9 A-Z! #$%&; ’()- @ ^ _` {} 和任何扩展字符。 扩展字符的有效字符编码取决于设置的代码页。 在LFN支持的系统下;=[]和空格也是有效的对象名称,除路径名末尾外,空格和点可以位于任何位置


  FAT 文件系统对卷上的对象名称不区分大小写。 FAT 卷上的对象名称在不区分大小写的情况下进行比较。 例如,这三个名称 file.txt,File.Txt 和 FILE.TXT是相同的。 扩展字符也是这样的规则。*** 在 FAT 卷上创建对象时,自动将转换为大写后的名称记录到 SFN 条目,并且在启用 LFN 功能时将原始名称记录到 LFN 条目。***
  对于 CJK(DOS / DBCS)的 MS-DOS 和 PC DOS,扩展字符被记录到 SFN 条目而没有大小写转换,并且区分大小写。 当 DOS/DBCS 系统在卷上创建任何具有扩展字符的对象时,这会导致与 Windows 系统兼容的问题; 因此,不应在这些系统共享的FAT 卷上使用具有 DBCS 扩展字符的对象名称。 FatFs 使用 DBCS 配置(DOS/DBCS 规范)仅对非 LFN 的扩展字符区分大小写。 但在 LFN 配置中,FatFs 对扩展字符(Windows NT规范)不区分大小写。

字符编码 第一阶段

  美国最初发明计算机后,首先遇到了字符编码的问题,他们想了半天,最终发明了采用一个字节(8 个比特位)一共可以组合出256(2的8次方)种不同的状态的方式表示他们的语言字符,对于他们来说足够了。而且早年的 ASCII 只定义了 128 个字符(可打印的 96 个),剩下最高位为 1 的 128 个码位算是空出来的。

第二阶段

  第二阶段,计算机开始流行,原来的 128 个已经不够用了,于是就启用了原来空着的高 128 个。从 128 到 255 这一页的字符集被称”扩展字符集“。IBM 搞 PC 机的时候定义了 codepage 437,把高 128 个码位也用上了。然而,计算机继续流行,现在的 256 个字符也不够用了,于是就到了第三个阶段!

第三阶段

  ASCII 无法表示其他国家的文字,例如中文、日文、韩文等。人们就想到的一种办法:用两个 byte 来表示一个字符。ASCII 不是空出来了高128个码位吗?第一个 byte 在这高128里取值,再和第二个byte结合就可以表示最多 128x256 = 32768 个字符了。程序在处理字符串的时候,遇到有 byte < 128 的就认为是 ASCII,遇到 >=128的就把下一个 byte 也读进来,换算成一个字符。我国的第一版字符编码 GB2312 编码就是这个方案的实现,其他国家也都有各自的实现!后来我国发现 GB2312 还是不够用,于是更改了表示策略扩展成了 GBK;再后来,GBK 无法表示某些少数民族的语言文字,我国再次扩展成 GB18030。
  这种编码的方法,被称为 DBCS(Double-Byte Character Set, 双位元组字元集)。

第四阶段

  每个国家都有自己的 DBCS 实现方式,这就导致了各个国家的字符编码方式不一样!比如我国的的不同地区(香港、台湾)的 DBCS 实现方式也是不同的!这个时候 ISO(国际标谁化组织)站了出来解决这个问题。他们的方法简单粗暴:废除了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号 的编码!他们打算叫它 “Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode”。举个例子,原来各地区的编码就好比方言,而 Unicode 就是全世界的官方统一语言。
  需要注意的是,Unicode 仅仅是规定了字符的表示规则,但是没有实现!Unicode 有多种实现方案:主要有 UTF-8,UTF-16,UTF-32 等。如果对于字符集感兴趣,自行去 Google 查阅相关资料!

编码页(Code Page)

  编码页(Code Page),也称内码表,是由 IBM 的引入的一个概念。想当年,IBM 作为第一批计算机制造者,风光无限!为了可以灵活处理计算机的输入问题,他们在计算机中引入了用一张表的形式来标识编码的这种方式。编码页就是一个经过挑选的以特定顺序排列的字符内码列表。
  后来,微软开始壮大,编码页被微软用来处理不同的地区的编码问题。每个地区的编码在 Windows 操作系统中,都有一个对应的编码页。这样,Windows 就可以根据不同的地址,以该地区的编码来显示该地区的文字了!新的 Windows 系统好像都开始使用 Unicode 编码了
  字符编码的不同将影响我们使用的字符串相关的函数,错误的编码选择将导致字符串函数出现操作失败等不可预知的错误!举个例子,Windows 系统的 API 中,很多都是要区分字符集的,用过 Win32 编程的人应该深有体会!比较乐观的是,如果不涉及底层,我们通常不用去关心字符的编码处理,系统会为我们来处理这个问题。但是,看 FatFs 这样的文件系统,字符编码是必须要考虑的!

Unicode API

  FatFs 根据用户配置,路径名以 ANSI/OEM 或 Unicode 来输入/输出。 FatFs中的函数中,指定路径名的参数类型定义为 TCHAR。 默认情况下,它是 char 的别名,用于路径名字符串的代码集是由 FF_CODE_PAGE 指定的 ANSI/OEM。 当FF_LFN_UNICODE 设置为 1 或更大时,TCHAR 的类型将切换为正确的类型以支持 Unicode 字符串。 当此选项指定 Unicode API 时,支持全功能 LFN 规范,并且 Unicode 特定字符(如✝☪✡☸☭)也可用于路径名。 它还会影响字符串I/O函数的数据类型和编码。 要定义文字字符串,_T(s)和 _TEXT(s)宏可用于自动选择 ANSI/OEM 或 Unicode。 下面显示的代码是定义文字字符串的示例。

f_open(fp, "filename.txt", FA_READ); /* ANSI/OEM string (char) */ f_open(fp, L"filename.txt", FA_READ); /* UTF-16 string (WCHAR) */ f_open(fp, u8"filename.txt", FA_READ); /* UTF-8 string (char) */ f_open(fp, U"filename.txt", FA_READ); /* UTF-32 string (DWORD) */ f_open(fp, _T("filename.txt"), FA_READ); /* Changed by configuration (TCHAR) */ 卷管理

  FatFs 的正确工作需要每个卷(逻辑驱动器)的动态工作区,文件系统对象。 它通过 f_mount 函数注册/取消注册到 FatFs 模块。 默认情况下,每个逻辑驱动器都绑定到具有相同驱动器号的物理驱动器,并且卷装入过程中将扫描驱动器上的 FAT 卷。 它读取引导扇区,并按照扇区0为SFD格式、第一分区、第二分区、第三分区和第四分区为 FDISK 格式的顺序检查它是否是FAT引导扇区。
  当配置选项指定 FF_MULTI_PARTITION = 1 时,每个单独的逻辑驱动器都绑定到卷管理表(PARTITION VolToPart[FF_VOLUMES];)指定的物理驱动器上的分区。 需要由用户定义卷管理表(PARTITION VolToPart[FF_VOLUMES];)以解析逻辑驱动器和分区的映射。 以下代码是卷管理表的示例。

Example: "0:", "1:" and "2:" are tied to three pri-partitions on the physical drive 0 (fixed drive) "3:" is tied to an FAT volume on the physical drive 1 (removable drive)PARTITION VolToPart[FF_VOLUMES] = { {0, 1}, /* "0:" ==> 物理驱动器 0, 第 1 个分区 */ {0, 2}, /* "1:" ==> 物理驱动器 0, 第 2 个分区 */ {0, 3}, /* "2:" ==> 物理驱动器 0, 第 3 个分区 */ {1, 0} /* "3:" ==> 物理驱动器 1, 自动检测 */};

下图显示了 FatFs 卷管理方式:

使用多分区配置时需要考虑一些因素。

具有两个或多个已安装分区的物理驱动器必须是不可移除的。 禁止系统操作时更改介质。只能指定四个主分区。 不支持扩展分区。Windows不支持可移动存储上的多个卷。 其只能识别第一个分区。 参考 FatFs 官网文档 http://elm-chan.org/fsw/ff/doc/filename.htmlWindows 官方中的字符编码

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。