写在前面

本文的内容部分来自于 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 name FF_FS_RPATH == 0 FF_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 官方中的字符编码

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

  1. python url解码_对python中url参数编码与解码的实例详解

    一.简介 在python中url,对于中文等非ascii码字符,需要进行参数的编码与解码. 二.关键代码 1.url编码 对字符串编码用urllib.parse包下的quote(string, saf ...

  2. js php base64,JavaScript实现Base64编码与解码的代码详解

    本篇文章给大家分享的是jJavaScript实现Base64编码与解码的代码详解,内容挺不错的,希望可以帮助到有需要的朋友 一.加密解密方法使用//1.加密 var str = '124中文内容'; ...

  3. nmmqq.php?/lspc.html,html中的图片直接使用base64编码后的字符串代替详解

    网页中的图片是使用base64编码后的字符串代替了,这个叫做Data URI scheme,下面有个不错的示例,大家可以参考下 最近来了一个网页,里面有图片,但是却没有引用外部的图片资源,很好奇.查看 ...

  4. java 置位_java安全编码指南之:Mutability可变性详解

    简介 mutable(可变)和immutable(不可变)对象是我们在java程序编写的过程中经常会使用到的. 可变类型对象就是说,对象在创建之后,其内部的数据可能会被修改.所以它的安全性没有保证. ...

  5. java中的getnumber怎么用_java安全编码指南之:Number操作详解

    简介 java中可以被称为Number的有byte,short,int,long,float,double和char,我们在使用这些Nubmer的过程中,需要注意些什么内容呢?一起来看看吧. Numb ...

  6. python怎么安装myqr模块-python二维码操作:对QRCode和MyQR入门详解

    python是所有编程语言中模块最丰富的 生活中常见的二维码功能在使用python第三方库来生成十分容易 三个大矩形是定位图案,用于标记二维码的大小.这三个定位图案有白边,通过这三个矩形就可以标识一个 ...

  7. python怎么安装myqr_python二维码操作:对QRCode和MyQR入门详解

    python是所有编程语言中模块最丰富的 生活中常见的二维码功能在使用python第三方库来生成十分容易 三个大矩形是定位图案,用于标记二维码的大小.这三个定位图案有白边,通过这三个矩形就可以标识一个 ...

  8. 【5年Android从零复盘系列之二十】Android自定义View(15):Matrix详解(图文)【转载】

    [转载]本文转载自麻花儿wt 的文章<android matrix 最全方法详解与进阶(完整篇)> [5年Android从零复盘系列之二十]Android自定义View(15):Matri ...

  9. SAP UI5 应用开发教程之一百零二 - SAP UI5 应用的打印(Print)功能实现详解试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 作者简介 Jerry Wang,2007 年从电子科技大学计算机专业硕士毕业后加入 SAP 成都研究院工作至今.Jerry 是 SAP 社区导师,S ...

最新文章

  1. Java中方法重载和方法重写的区别
  2. linux多线程九宫格,项目实战:Qt九宫格图片资源浏览器(支持window、linux、兼容各国产系统,支持子文件夹,多选,全选,图片预览,行数与列数设置等)...
  3. python符号大全_python吊打Excel?屁!那是你不会用!
  4. 华为鸿蒙系统支持什么手机_华为手机支持升级鸿蒙OS的EMUI 11系统55款机型名单公布...
  5. JavaScript重定向到其他网页
  6. jquery固定table第一列或第一行
  7. 【论文阅读】Zero-Resource Knowledge-Grounded Dialogue Generation
  8. ubuntu18 配置静态IP地址(详细版)
  9. 从yield到yield from
  10. hdu 1535 Invitation Cards
  11. 共享单车登录显示服务器未响应,ofo共享单车出故障了吗?ofo共享单车无法登陆、连接不上、无法结算怎么回事?[图]...
  12. Bayesian Nonparametric Learning of Cloth Models for Real-Time State Estimation
  13. 中通快递2019年第三季度营收同比增长24.4%至52.66亿元
  14. java怎么添加商品信息_Javaweb网上商城项目实战(20)添加商品到购物车
  15. 树莓派 Raspberry Pi (bullseye)更换阿里云源方法
  16. 初学Java常用设计模式之——装饰器模式
  17. 已知圆上任意两点求圆心和半径_已知圆上三点坐标求圆心和半径
  18. 将目录专为源码html,LiteOS移植笔记
  19. 免费分享我的匿名邮件群发系统,可匿名发送: 163 126 139 gmail qq 21cn 263 及各类企业级邮件
  20. matlab自带的插值函数interp1的几种插值方法

热门文章

  1. 【机器视觉】图像处理 -- 上采样和下采样 数据增强 稀疏矩阵
  2. 熬夜是不是真的会暴毙啊?
  3. CS品牌SD NAND VS TF卡 SD NAND和TF卡的区别
  4. 使用Umami自建网站流量统计
  5. 注入(injector)
  6. php支付接口,代付、感悟
  7. 肖sir___埋点测试
  8. Codeforces Round #723 (Rated for Div 2)
  9. 智能家居产业预测:2015年将是关键年
  10. 二十分钟构建猫VS狗图像分类器