FatFs 之二 路径规则、字符编码、编码页、卷管理详解

写在前面

本文的内容部分来自于 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
  控制字符(\0 到 \x1F)被识别为路径名的末尾。 路径名中的前导或嵌入空格在 LFN 配置中作为名称的一部分有效,但在非 LFN 配置中,空格被识别为路径名的末尾。 两种配置都会忽略尾随的空格和点。
  在默认配置(FF_FS_RPATH == 0)中,它没有像面向操作系统的文件系统那样的当前目录的概念。 卷上的每个对象始终以从根目录开始的完整路径名指定。 不允许使用点目录名称(“.” 或者 “…”)。 标题分隔符被忽略,它可以存在或省略。 默认驱动器固定为驱动器 0。
  启用相对路径(FF_FS_RPATH> = 1)时,如果存在标题分隔符,则从根目录开始遵循指定的路径。 如果没有,则从 f_chdir 函数设置的驱动器的当前目录开始跟随。 路径名也允许使用点名称。 默认驱动器是 f_chdrive 功能设置的当前驱动器。

Path nameFF_FS_RPATH == 0FF_FS_RPATH >= 1
file.txt驱动器 0 的根目录中的文件当前驱动器的当前目录中的文件
/file.txt驱动器 0 的根目录中的文件当前驱动器根目录中的文件
驱动器 0 的根目录当前驱动器的当前目录
/驱动器 0 的根目录当前驱动器的根目录
2:驱动器 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 时代采用的命名方法,如下图所示:
在这里插入图片描述

  • 8: 是指文件名或目录名的主体部分小于等于 8 个字节,目录名是没有扩展名的,文件名可以有个扩展名,表示文件的类型
  • . : 分隔符,将文件名与扩展名分开
  • 3: 是指文件名的扩展名部分(扩展名)小于等于 3 个字节。

根据 8.3 格式的命名规范,多余的字符将被忽略,DOS 默认的做法是将多余的字符替换为 ~ x 。其中 x 是数字,例如,123456~8.TXT。并且如果一个文件没有扩展名,那么它后面的点将没有意义,即:file 和 file. 是同一个文件。
  此外,FAT 文件本身不区分大小写,但是在绝大部分系统中,都是使用名字会被统一转换为大写!FatFs 也是如此!

长文件名

  长文件名(Long File Name,LFN),凡是文件的基础文件名(不包含扩展名)超过 8 字节或扩展名超过 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不支持可移动存储上的多个卷。 其只能识别第一个分区。

参考

  1. FatFs 官网文档 http://elm-chan.org/fsw/ff/doc/filename.html
  2. Windows 官方中的字符编码
  • 11
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZC·Shou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值