您好,欢迎来到尚车旅游网。
搜索
您的当前位置:首页振南的znFAT(全5章)

振南的znFAT(全5章)

来源:尚车旅游网
振南的znFAT

--单片机上的FAT32文件系统--单片机上的单片机上的FAT32文件系统

前言

1、znFAT是什么?

关于znFAT,也许您从未耳闻,这是因为振南并没有去宣传,也很少向人提起,基本都是私下在作,在这个过程中与不少网友和爱好者进行了交流,他们为znFAT提了不少的建议和需求,使znFAT可以不断改进和扩充。也有不少人建议我开源,在这种要求之下,我在网上公开了一部分代码,果然是受到了很大的关注。但我要说的是,先前没有全部开源是因为我自认为znFAT还不够完善。现在,znFAT经过一遍遍的测试以及在实际工程中的应用,已经较为完善了。我不敢说znFAT已经一点问题没有了,但如果一直是我一个人在作,它也难以得到更进一步的发展,所以谨以此书,向大家介绍znFAT的研发与实现过程。

znFAT到底是什么?znFAT是振南原创的一种方便移植于各种微处理器上的开源的FAT32文件系统解决方案。2、znFAT能用来作什么?

这是最核心的一个问题,就如同筷子用来吃饭、雨伞用来挡雨,各有各的功能,所以才有存在的必要。简单来说,znFAT最重要的用途就是在存储设备上,如SD卡、CF卡等等,实现FAT32文件系统,进行各种文件操作,并保证与windows等操作系统上的FAT32文件

系统相兼容。

虽然我们每天都在用电脑,在与文件打交道,但不一定每个人都知道有文件系统这种东西,或者不了解它的运行机制。而我要说的是,正因为计算机、MP3、手机等等现在能这么普及,很大程度上是因为有文件系统。

FAT32文件系统是一种机制,或者是一种智慧,更如一个主管,可以将存储器上的数据有机的组织为一个文件,并向我们提供针对于文件的各种操作,比如创建文件、读取文件等等。

znFAT是一套解决方案,也就是一套实际可以看到的代码,更通俗的说就是用C语言对FAT32的实现,用于运行在某一种微处理器上,并在某一种存储设备上真正实现FAT32中的各种文件操作。至于znFAT中都实现了哪些功能,在后面的介绍中大家会有全面的了解,同时也就能了解到编写一套文件系统解决方案所要花费的心血了。

3、为什么要自己从0写,不是有现成的方案吗?

能问出这一问题的人,想必不是初学者,因为文件系统这种东西已经算是比较高级的应用了,所以一般人在初学阶段是不会接触文件系统的。只有有了一定经验,进入实际项目的人,才会越来越发现文件系统的重要。

为人所熟知的现有的文件系统有FATFS、uc/FS等等,由来已久,并且也在不断的改进发展,拥有很大的应用人群。这些现有的方案,都向使用者提供了源代码,方便移植到各种平台上。但稍有了解的,

就会发现,这些解决方案都来自于国外,或是公司,或是研究团体,从而造成源代码很难被读懂,想要深入去了解文件系统是怎样实现的,比较困难。所以如果能原创性地编写出一套完善的文件系统解决方案,并配以相应的教程和应用实例,就可以使我们对文件系统有更深刻的了解。理解了它的真谛,我们就可以去实现那些现有方案中没有实现,而我们又急于实现的功能,一切工作都变得非常灵活。

在这里,您可能还会问,难道国内就没有成形的文件系统解决方案吗?我要说,有!比如沁恒电子、各个开发MP3、MP4、手机的公司,我想都会有专门的人去研究文件系统并予以实现,但最重要的一点,他们是不会开放源代码的,更不会告诉你他们是怎样实现的!4、FAT32文件系统到底有多复杂,好不好学?

虽在FAT32文件系统协议文档中讲的东西很多,乍看起来很零乱,使人无从下手,但只要耐住性子多看几遍,真正的看进去了,就会发现FAT32文件系统内容虽多,但层次分明,逻辑缜密。最后你会产生这样的想法,只要肯下功夫,就一定能写出一套不错的方案来。

不过,如果是自己从0来研究FAT32文件系统,还是不太好弄明白的,这也是本书的初衷,振南的任务就是把FAT32文件系统掰开了揉碎了,让您轻松接受,并感觉到FAT32文件系统设计上的一些微妙之处,感叹微软令人佩服的创造力(FAT32文件系统的老家是微软!)

5、有了znFAT我们能作出些什么?

当我们真正把FAT32文件系统研究明白了,学会用znFAT在存

储设备上进行各种文件操作了,这个时候,znFAT就成为了我们得心应手的工具了。也就是说,利用znFAT我们就可以开始更进一步的开发了。而此时我们开发的层次已经与以前截然不同了,以前我们读写数据也许就是直接在存储器的扇区里或存储单元里读写,而现在我们是在文件里进行读写,而且我们读写的数据与windows是相通的了。

我们可以作出更多精彩的实验和产品,比如SD卡MP3播放器、可插接U盘的数码相框、CF卡电子书等等。可以说,如果我们具有了操作文件的能力,很多问题都可以迎刃而解,很多实验都变得很简单了。

6、znFAT是不是需要特定的硬件才能实现?

其实znFAT研发过程中的难题有很多,除了FAT32文件系统本身的复杂度外,还有就是实际平台的硬件资源了。研发znFAT的一个重要指标就是可移植性,不光包括znFAT本身的程序接口要易于移植,另外更为重要的就是占用资源量,占用资源越少,越容易向一些低端的微处理器上移植。振南在研发znFAT的过程中所使用的硬件是STC12C5A60S2(STC公司出产的一种1T增强型51核单片机,片内有1280字节的RAM)、1G的SD卡与CF卡各一张(其实就是基于振南的“天狼星精华板”上的硬件资源,这里为什么要有两种存储设备,SD卡与CF卡,到后面您就明白了!)

应该说振南所使用的硬件已经是非常简陋了,也正是因为硬件资源较为贫瘠,才能写出更为精简高效的代码来,以节省资源。所以振南在编写程序的过程中,不光要考虑功能的实现,还要计算RAM等

资源的用量。现在现在为止,znFAT实现所有功能所需要的RAM资源只有900多字节,其中有512字节的扇区数据缓冲区,也就是说,znFAT实现FAT32的逻辑只用了400多字节。而常用的单片机、ARM、DSP等芯片RAM一般也在几K到几十K字节,所以znFAT可以轻松向这些芯片进行移植。7、本书都会讲哪些内容?

在本书中,FAT32文件系统协议及基本的原理是肯定要讲解的,然后就是znFAT各项功能的具体实现。由于文件系统不可能孤立存在,必须要运行于某一种微处理器上,因此要把STC12C5A60S2单片机一些基本用法讲一下;其次还要基于一种存储设备,所以还要讲解SD卡与CF卡的驱动原理与具体实现。除此之外,还有程序的调试方法、相关软件的用法等等。总之,此书不乏要讲的东西。

前言中振南用自问自答的方式,也许让您粗略了解了FAT32文件系统及znFAT。此时的你,估计还是一个门外汉,下面就让振南慢慢地把您让进屋来。

振南的znFAT

--单片机上的FAT32文件系统--单片机上的单片机上的FAT32文件系统

第一章FAT32文件系统初探

一开始我们先不讲FAT32诸多的技术细节,对于一个刚刚接触FAT32的人来说,了解它的一些由来和发展历程,以及与其相关的知识,我认为是十分有必要的。当然也不乏很多人已经对FAT32有了一定的认识,或者急切想学习FAT32的具体内容,那么您就可以跳过这一章,而直入主题了。

第一节从DOS说起要说起FAT32文件系统,追根溯源,还要从DOS时代说起。自1981年DOS被开发出来以后,经过不断的改进和发展,直到1987年,才成为一个真正优秀的、让微软立于霸主地位并为其带来巨额利润的系统。此时的DOS版本为3.3,又经过7年的时间,微软发布了DOS的闭关之作,这就是DOS7。

即使您不是研究计算机的,您也一定听过DOS,而DOS到底是什么?DOS与FAT32文件系统又有何等的关系?可能您没有深入的研究。DOS,字面上来说,就是DiskOperatingSystem,即磁盘操作系统。顾名思义,DOS向用户提供了在磁盘上进行相关操作的接口与服务。更通俗地讲,就是使我们通过它可以访问和操作磁盘上的目录与文件,比如创建目录、创建文件、读取文件数据、拷贝文件等

等。在很大程度上,DOS及其以后的Windows能够得到极大的成功,都得益于“文件”。有人会问,操作系统可以运行软件、可以管理任务,这些与文件又有什么关系?确切的回答是,这些与文件有极为密切的联系,起码软件本身就有可能是一个EXE文件,操作系统本身也会有很多的库文件,来作为软件运行的支持,软件运行中可能会产生一些文件……基本上一切操作系统上的各种应用都会与文件有关。这就奠定了文件系统在操作系统中的重要地位,对于DOS来说,它主要的工作就是管理磁盘上的文件与目录,文件系统自然是它的重中之重,核心中的核心了!这里就引出了DOS中所使用的文件系统,这也是当今盛行的FAT32文件系统的前身,至今仍在延用,即FAT12/16。

第二节Windows中的文件系统在微软的MS-DOS大行其道的时候,Windows已经在研制之中了,Windows1.0在1985年11月发布出来,其实就是一个图形界面的MS-DOS,原来的命令输入方式变为了鼠标点击方式。如图1.0所示为Windows1.0的界面。

图1.0Windows1.0的界面

虽然Windows1.0已经有了较为华丽的界面,但它的功能与MS-DOS基本上差不多,主要工作就是进行磁盘文件和目录的管理。其实从某种意义上来讲,MS-DOS与早期的Windows并不能算是操作系统,他们在任务管理方面仍然较弱。

Windows继1.0之后又发布了2.0、3.0,尤其是1990年发布的3.0是一个全新的版本,并取得了巨大成功,两年内销售量就达到了1000万份拷贝。随后又相继发布95、98、2000、XP等等,其中95真正使Windows大众化,首次引入了“开始”按钮和任务栏,大大方便了用户的使用,也使其成为了一种标准模式,此后的Windows中仍在延用,直到今日。98在95的基础上进一步改进,这里要说的是在这一版本中引入了较为成熟的FAT32文件系统,并马上体现出了其自身的优势。如图1.2,是Windows98的界面。

图1.2Windows98的界面

其实FAT32文件系统首次投入使用是在Windows95OSR2中,这

个版本很少有人知道,俗称为Windows97。这也是FAT32文件系统的一次尝试,在很多方面还不是很成熟,所以微软并没有进行宣传。从这里,我们也可以看到文件系统在Windows中的份量。

纵观微软操作系统产品的发展史,从DOS到Windows,再从Windows1.0到现在的Windows7,规模越来越大,功能也越来越强大,但文件系统在其中的地位从未动摇,并且得到了极大的发展,所以我们研究FAT32文件系统是十分有意义的。

第三节FAT32是FAT文件系统的终级演化FAT,字面上的意思是文件分配表(FileAllocationTable),它可谓是FAT文件系统的特色,也是灵魂。

其实FAT文件系统早在1977年就已经由比尔·盖茨和马斯·麦当劳发明了,为得是管理磁盘。1980年被添·彼得逊的86-DOS操作系统(86-DOS可以看作是MS-DOS的前身)采用。

FAT文件系统的最基本思想就是使用链式结构来记录文件数据的位置,这样就允许文件数据的存放可以不连续,从而极大的提高了磁盘的利用率。FAT文件系统又分为不同的版本,用后面的数字进行区别,分别有FAT12、FAT16、FAT32,不同的版本在支持的分区容量、簇大小等方面都不尽相同。

FAT12是FAT文件系统中最古老的文件系统了,在DOS3.0之前使用。它采用12位文件分配表,并因此而得名(以后的FAT文件系统都按照这样的方式在命名)。FAT12可以管理的磁盘容量是8M。这在当时,它的磁盘管理能力已经算是很强了,因为当时还没有硬盘,

主要还是在软盘上应用。直到现在,我们仍然可以看到FAT12的身影。

FAT16是使用时间最长的FAT文件系统了。在DOS2.0使用的过程中,其实磁盘的容量也在不断扩大,从而造成FAT12无法管理较大容量的磁盘,这样FAT16在DOS3.0中应运而生。除了采用了16位的分区表之外,FAT16和FAT12在其他地方都非常的相似。前期的FAT16管理磁盘的能力实际只有32M,到了1987年DOS4.0的时候,FAT16发展到可以支持128M,随后又到达2G。在整整10年的时间里,存储技术得到突飞猛进的发展,磁盘容量也与日俱增。于是在1997年发布的Windows95OSR2中首次引入了FAT32文件系统,这也是本书的主角。

FAT32文件系统是FAT文件系统的最后一个产品。和它的前辈一样,这种格式采用32位的文件分配表,磁盘的管理能力大大增强。FAT32文件系统最大可以支持2T的磁盘,但在WindowsXP中实际最大只能支持32G。FAT32是对前面FAT文件系统的传承,但并不是简单加长了文件分配表项的长度,而是一个全新的产品。比如FAT32可以重新定位根文件夹;使用文件分配表的备份副本,而不是使用默认副本;根文件夹是成为了普通的簇链,从而使得根文件夹下的文件或目录不再有数量……对于这些新的特性,也许你暂时还不知所云,或者不能深刻认识到它们的好处,这是因为您对FAT32文件系统还没有足够的了解。

在后面章节的学习中,您会渐渐为FAT32的巧妙设计赞叹不已!

第四节随处可见的FAT32文件系统在粗略的了解FAT32文件系统之后,您可能要问了,FAT32文件系统再强大,那也是计算机上的事情,与单片机底上的应用又有什么关系呢?在笔记本电脑都是奢侈品的年代,这样的质疑是有道理的,脱离开了计算机,人们确实在日常生活看不到文件系统的存在。

到了今天,嵌入式技术极速发展,手持式设备,如手机、MP3、数码相机、DV等等,比比皆是,FAT32文件系统已经早已挣脱了计算机的束缚,被应用在了更多领域之中。手机、DV中影音文件的存储与读取;MP3中音频文件的录制与播放……您觉得这些应用中是什么在起着重要的作用?那当然是文件系统!而其中占主导地位的就是FAT文件系统,而FAT32就是FAT文件系统中最经典,最强大的一个版本!

在嵌入式设备中,更确切的说,是在嵌入式微处理器及相应的存储设备中实现FAT32文件系统,意义是十分重大的。它使得在嵌入式设备上创建的文件及写入的数据,可以为Windows等支持FAT32文件系统的操作系统直接识别和读取;反之,嵌入式设备上也可以识别和读取操作系统上创建的文件及其数据。我们可以举一个简单的例子来进行说明:拿MP3来说,在Windows将MP3的存储器格式化为FAT32文件系统,并向其中拷入音频文件,比如MP3、WMA等等。将MP3从计算机上拔下后,它就可以识别出存储器上的相应文件,打开文件、读取数据送到MP3解码电路,这样就实现了音频播放。相反的,一些MP3是可以录音的,会将声音录制为WAV文件,

直接记录在存储器中,如果这个WAV文件是遵循FAT32文件系统的话,那么我们可以在操作系统上直接看到MP3中的这个WAV文件,直接用WMP或MMC等播放器播放。我想只要是玩过MP3的人,一定有这种经历。

那么没有文件系统到底行不行呢?回答是,行!但这样的设备不是很专业的人估计就玩不转了。还拿上面的MP3例子来说,在录音的时候,如果MP3中没有文件系统,那么它可能采用的方式就是把声音数据直接写到存储器的物理扇区中去。这样把它放到操作系统上去之后,操作系统根本就不知道这些声音数据在哪些扇区上,更无法将它们识别为一个文件。所以虽然数据确实在存储器中,但一般人是没办法把它们读出来了。除非你是这方面的高手,知道声音数据记录到了哪些扇区,也知道如何去读取物理扇区,还要知道怎么把这些数据还原为文件,这样的工作估计没几个人会作,即使是在硬件方面很有经验的人,也要研究几天。如果真是这样,那么这样的MP3又有谁会买,MP3也绝不会像今天这样大众化,而可能只会成为少数高手眼中的玄妙之物。

总而言之,文件系统已经广泛应用于各种设备之中,正是因为文件系统的存在才使得众多的电子产品变得越来越普及,连老人和小孩都可以使用自如。那些物理上的数据,在人们面前已经变成了一个文件的图标了,要访问他,只要用手中之笔轻触即可!如图1.3,是PPC上的文件浏览器的界面。

图1.3PPC上的文件浏览器的界面

到这里我们已经了解了文件系统的重要了,可以说它是物理设备与我们的上层应用的桥梁,使我们直接以文件的方式看到数据,而不用了解数据在物理设备中的存储情况和诸多细节,让我们把更多精力放在应用层的软件开发和功能的实现上。

这里要说的是,要自己在嵌入式的微处理器上实现FAT32文件系统,也绝非是一件易事,它要求你懂得微处理器的使用和开发方法、存储设备的驱动程序开发、FAT32文件系统的运行机制、硬件及软件的测试方法等等,总之,这已经不是一个简单的HelloWorld!!程序了,而是一个较为复杂艰巨的工程。但即使是这样,我们也仍有信心将它作好,因为我们拥有最重要的两样东西:坚韧不拔的毅力和浓厚丰富的开发经验!!

从下一章开始,我们就真正进入到去FAT32文件系统的学习研

究中了,了解FAT32文件系统中的各种技术细节以及会遇到哪些问题,大家也可以看到在znFAT中是如何将FAT32文件系统付诸实现的。

好,欢迎步入振南的znFAT——单片机上的FAT32文件系统!!

振南的znFAT

--单片机上的FAT32文件系统--单片机上的单片机上的FAT32文件系统

第二章让思想与FAT文件系统接轨

在前面我们已经稍微的提到过,FAT32文件系统是基于一种链式结构的。那么这种链式结构为什么要被提出来?怎么提出来的?它又被用来解决怎样的问题呢?……这一系列的问题将在本章中得到解答。

我想在出现了对磁盘数据的管理需求的时候,人们想到的方法应该不会直接就是链式结构,而会是一种更为直接的方式,这些方式也许是最初FAT文件系统研发中的一些中间形态,最终才出现了数据的链式存放方式,人们为的就是数据存储的更高效率以及磁盘空间更有效的利用。让我们从最原始的需求出发,经历文件系统设计中的几个阶段,看到几种可能的解决方案,最终自然而然达到与FAT文件系统的研发者不谋而合,此时,我们的思想就与之接轨了!

第一节最最简单的文件系统如果让我们自己来设计一个文件系统,我们会怎样来设计?那么我们还要再明确一下文件系统要解决的问题。文件系统简单说来就是让我们在给定文件名之后,就可以找到相应的数据。其实就是实现一种映射,即文件名与数据所占用的存储单元之间的映射。好,在我们聪明的头脑中可能会马上浮现出这样的模型来。如下图2.1所示,最最简单的文件系统示意图。

图2.1最最简单的文件系统示意图

这样一个模型算是一个最原始的文件系统,它实现了文件名与数据的最直接的映射。如图中所示,它将多个文件一个挨着一个存放在一起。每一个文件都有自己的文件标记,用来表示这是一个文件的开始,在文件标记我们可以设置一些参数来记录与文件相关的一些信息,比如文件名、文件的大小、文件的访问时间等等。文件的数据就直接放在文件标记的后面,并占用连续的存储空间。确实,在这种模型中,只要我们给出文件名或其它信息,我们就可以找到符合条件的文件标记,并获得后面的数据。但如果您稍动脑子,就会发现,这个模型存在很多的问题。

1、查找文件的效率非常低。

当我们要访问某一个文件的时候,其实就是查找这一文件的文件标记,就要从存储器的第一个存储单元开始,把存储单元中的数据全部读出,查找有没有文件标记,如果有还要看是不是与要查找的文件标记相吻合。这样一来,查找一个文件所花费的时间就变得不确定了。比如,如果我们要访问的是“文件1”,那么我们一下子就可以找到它,但是如果我们要访问

的是“文件5”,那就必须在经历了前面的所有存储单元之后才能找到它。可想而知,如果我们要访问的文件位于磁盘的最后面,那么我们将遍历整个磁盘,这是无法容忍的!所以,一个优秀的文件系统将要解决的一个重要问题就是:让访问文件的效率得到保证。2、不可能为文件追加数据。

这一点是显而易见的。这种模型中,文件数据的存放都是紧挨着的。如果想为某一个文件追加数据必然会覆盖后面文件的文件标记及数据。文件系统的基本任务是保证文件数据不受到破坏,因此注定这种模型是极不科学的。所以,这又要求我们设计的文件系统一定要易于进行文件数据的更改,并保证文件数据的正确性与完整性。3、不能有效的利用磁盘空间

也许这一点您还没有意识到。那么我们可以看看这样一种情况。在上图中,如果我们把“文件3”删除,也就是文件3所占的存储空间空闲出来了,您可能会说,那直接在文件标记中作上标记,说明此文件已无效就可以了。嗯,确实是这样。但如果我们这个时候又要存放一个新文件,那么首先考虑的就是如何来利用这个空闲的存储空间。如果新文件的大小不大于原来的文件,那么没有问题,直接把新文件放在这里就好了。但如果新文件的大小大于原来的文件的话,那么这个空闲的存储空间就不足以来容纳这个新文件了,唯一的方法就是到后面

另外寻找大块而且连续的存储空间。这样,这个空闲的存储空间就浪费了,或者一直等到有合适的新文件的时候,它才能得以利用。所以,从这一方面来看,这种原始的文件系统模型也是不科学的。有效合理的利用磁盘空间也是我们要解决的一大问题。

上面列举的是我们能够想到的这种模型的不足之处,甚至可以说是重大缺陷!急切地需要一种新的模型来改进它。

第二节对原始模型的改进鉴于原始模型的诸多问题,这里提出改进的方案。如图2.2所示,是一种改进模型。

图2.2一种改进后的文件系统模型

这个改进后的模型最显著的特点在于它在文件的每一个数据单元中都加入了一个标记。这个标记用来指明此数据单元是属于哪一个文件的、是此文件的第几个数据单元、此数据单元是不是最后一个数据单元等信息。我们来看看这样有什么好处。

1、查找文件效率更高

与原始模型不同的是,此模型将文件标记都提到了数据单

元的前面,这样一来,我们就不需要再进入到数据单元之中,对全部数据进行分析了。只需要对数据单元中前面文件数据标记部分的数据进行分析就可以了。当然,我们要查找的是诸多文件数据标记中的第一个标记,它是文件数据的开始。

这种改进模型固然把文件查找的效率提升了。但实质上,它并没有彻底解决问题。查找文件标记时仍然是采用遍历存储单元的方式,只是在文件标记的处理方式上有所改进而已,所以原始模型中的问题仍然存在。其实此时,只要我们再引入一个新的思想问题就可以迎刃而解,在这里先卖个关子,大家在下一个模型中就可以看到。2、文件数据的更改更为灵活

我们可以发现,在改进模型中,每一个数据单元都有自己的信息标记,就像是给它们都发了个身份证,数据单元的这种特性就决定了它新的优点。比如,我们要为“文件3”追加数据,如图2.3所示。

图2.3为“文件3”追加数据

如果追加的数据长度不大于“文件3”最后一个存储单元

的剩余空间,那么这些数据就可以直接添入其中就可以了。而如果要追加的数据长度比剩余空间要大,而又不能覆盖后面的文件,那么我们可以在后面的某一个空闲存储单元中创建一个新的文件数据标记,比如“文件3:3”,将数据添入其中。

这其实已经有了一点FAT文件系统的影子了,它允许数据的存入不连续了。只是受到了文件访问效率的牵制,也就是上面所说的第一个问题。如果某一个文件的数据单元被记录在了磁盘的末尾的话,那我们要读到这些数据,就必须遍历前面所有的存储单元,这同样也是不能容忍的!

也许您早已想到,造成文件访问效率低的主要原因就是我们不知道文件数据都分布在哪里?所以我们只能傻呵呵的一个个去找,CPU很卖力,却得不到好的效果。说白了,就是费力不讨好。

3、存储空间的利用上貌似清晰,其实并不合理

如果在这种模型下删除掉“文件3”,那么后面新的文件无论大小都可以有效利用空闲空间,因为它多出的数据部分可以到后面去寻找空间,只要为数据打上标记就可以了。似乎已经把空间利用问题处理的很好了,实则不然。那些数据中的标记的作用是为数据标识身份用的,它们与数据本身掺杂在一起,这在实际进行数据的读取与处理时会带来麻烦。一个优秀的文件系统要作到数据与信息存储上的分离,这样才能达到较高的效率。而这一模型CPU一会儿处理信息,一会儿处理数

据,显然影响了文件数据的连续性及访问效率,这是需要进一步改进的地方。

另外一个问题应运而生,由于数据的存放不再连续,从而造成了一些存储空间被浪费掉了。比如“文件1”“文件2”中最后存储单元中的空白部分,本身这些空间属于相应的文件,但又因为实际文件长度不足以填满它们,又不能被其它文件利用,所以被白白浪费掉了。其实这体现出了时间与空间的平衡问题,用相对少量的空间浪费换取效率上的提升,在很多情况下是划算的。就算是在FAT32这样一个完善的文件系统里,虽然存在这样的问题,对一些存储空间进行了舍弃。到后面我们就可以看到,这样作确实是利大于弊的。

第三节越来越接近FAT文件系统各种需求以及亟待解决的问题,都把我们引向了FAT文件系统的方向。在这节中提出的模型已经初露FAT文件系统的身形了。上一节中我们说只要引入一个新的思想就可以使文件访问效率低这一问题得到解决。这一新思想是什么呢?索引!我们来看图2.4中所示的模型。

图2.4带索引区的改进文件系统模型

在这种模型中将原来位于数据单元前面的信息都归纳到了专门的存储单元中,比如0号存储单元。其中记录的内容是这样的:文件1:1->2->3;文件2:4;文件3:5->6->7->9;文件4:8;……这样就够成了一个索引,通过它我们可以知道某个文件的数据的分布情况,而且文件数据的存放也更为合理,不再掺杂任何其它信息,使CPU可以专注于数据的读取和处理,不用再去分析哪些是信息,哪些是数据了。其实这一模型的好处不只于此,最重要的是他使文件访问的效率极大的提升了。我们要查找某个文件,只要在索引中查找就可以了,而不用去遍历整个磁盘。这个索引其实就相当于FAT文件系统中的FAT表,即文件分配表。索引中记录的内容,正是一种链式结构,最典型的,如“文件3:5->6->7->9”,它告诉我们数据单元5后面的数据在6中,6后面的数据在7中,7后面的数据在9中,其它文件的链式关系也依此类推。当然,在更改文件的数据时,相应的链式结构也要得到更新,才能真实的反映出文件数据的分布情况。

我们用自己聪明的头脑,提出了索引与链式结构,说明我们与当初FAT文件系统的发明者一样,也具有了相同的思路。这比别人向我们诉说FAT文件系统有多少优越,设计多少巧妙更有意义!

到这里,看似我们已经解决了不少的问题,但我们要明白一个道理,问题的解决从来都是与问题的出现相伴的,万物相生相克。此时,我们又有什么问题呢?

我们看到,索引里的文件标记(其中包含文件名等信息)与链式结构是掺杂在一起存放在专门的存储单元里的。这里好像并不是很合

理。我们希望它们单独存放在不同的地方,这样就极大的方便了文件的查找,因为在查找文件标记的时候,我们可以不用理会链式结构,两者截然无关。文件数据的开始位置,也就是链式结构的第一个节点由文件标记来记录。这里说的可能比较抽象,其实我们理想的情形是这样的,如图2.5所示。

图2.5链式结构与文件标记的分离

其实这里的记录诸多文件标记以及链式结构的区域就相当于我们FAT32文件系统中的目录与FAT表。

那么它们这两部分要占用多少的存储空间呢?也就是需要多少空间才能够容纳磁盘上所有存储单元之间的链式关系与文件标记呢?这确实是一个非常重要的问题。在这里我们先卖个关子,因为在FAT32文件系统中对这些问题进行了巧妙的解决,我们还是把好戏留在后面。当然,您在阅读后面的内容,由FAT32文件系统揭开答案之前,可以自己思索,看看您的解决方案是某与FAT32文件系统不谋而合。

这里可以给一个提示,记录链式关系的存储空间对于一个磁盘来说是固定的,而记录文件标记的空间却是动态的。

振南认为我们的模型演化到这里就告一段落,毕竟我们不是要自己白手起家,设计一套完善的文件系统,而是要研究现有的FAT32文件系统。这一章的内容主要就是为了让大家了解文件系统中要解决的问题以及如何解决。

总得来说,只要您明白了为什么要采用链式结构,就有了继续向下阅读本书的资本了。从下一章开始我们就要接触正而八经的FAT32文件系统了!

振南的znFAT

--单片机上的FAT32文件系统--单片机上的单片机上的FAT32文件系统

第三章谁格式化了我的SD卡

从这一章开始,我们正式接触FAT32文件系统。我们不会单纯讲枯燥无味的FAT32文件系统协议,振南认为这样于你于我都不是什么好事。我最不喜欢死板地陈述协议,估计你也不会喜欢这种条条框框的方式。所以我们还是从实际应用出发,结合我们的日常经验来讲,这样会事半功倍。

SD卡,我想,只要你用过数码相机、智能手机等设备,就一定接触过。只要你接触过,一切就好办了!我们就结合SD卡来讲解FAT32。

第一节关于SD卡1、为什么选用SD卡我们研究FAT32,必然要选择某种存储设备。因为FAT32不是孤立存在的,必须以某种存储设备为载体,就像我们思想不能凭空存在,必须信赖于头脑这个真实的硬件一样。那么选取哪种存储设备呢?这也是振南在研究FAT32初期提出的问题。综合各种考虑,它应该满足以下几点要求:

①易于购买。这一点是显而易见的,如果它根本就不存在,比如还没有被发明出来;如果理论上可以得到,但事实上很难实现,比如它只有美国的某一个特殊机构在使用;如

果它就在身边,触手可及,但价格很高,根本买不起,更不会忍心拿它来作实验等等,这些情况都会对我们的实验造成不便。总之,我们要从身边最常见的存储设备中选择。作最坏的打算,就算我们实验中把它烧毁了,我们还可以很方便的再买一个,继续我们的研究。

②资料齐全,驱动易于编写。也许您也有过这种情况,一个看起来很不错的硬件,比如一个显示屏、一个芯片等等,但苦于找不到相关资料,而让它永远躺在那里睡大觉。所以我们选择的存储设备一定要有很齐全的资料,这样我们才能有所参考,顺利的编写驱动程序。

③封装简单,易于焊接。存储设备放在那里,自己是不会工作的,都要有相应的电路才可以。这就需要我们作PCB,即印制电路板,或者用万用板来焊接。作PCB时,我们是需要为它绘制封装的,当然它的封装越简单越好。同时,如果存储设备不方便焊接,也会对我们的实验造成困难。比如一些引脚很密的FLASH芯片,或者引脚位于底部,只有用专用的焊接设备才能焊接的存储设备。

④存储容量大于FAT32的最低要求。FAT32不支持容量小于512M的分区,因此如果你买了一个128M或256M的存储设备,仍然无法研究FAT32文件系统,因为你根本无法把它们格式化为FAT32。

⑤接口简单,易于接线。其实我们接触最多的还是硬盘,

当然现在比较流行的SATA硬盘接口由于采用串行方式,所以接口比较简单,没有几条线。但老式的IDE硬盘,接口针数就很多了。这样不方便我们接线,同时由于单片机或微处理器的IO毕竟有限,所以这种接口较为复杂,接线较多的存储设备也不适用于我们的实验。

除了上面讲到的这些因素,其实还有很多,这里就不再一一列举了。下面我们来看看几种现在比较流行存储设备,经过比较,您就知道我们为什么选择SD卡了。如图3.1,当今流行的存储设备。

图3.1当今流行的存储设备

这些都是现在最为流行的存储设备,这意味着它们都可以很方便购买到。但它们却有各自的不足之处:

U盘:USB接口,驱动很难编写,通常需要加USB的主机控制器,提高了我们实验的成本和难度。

XD卡:专用于数码相机,相关资料比较少,所以不了

解应该如何来写它的驱动。其次,它的价格较高。

FLASH芯片:FLASH常被直接焊接在PCB上。由于较大容量的FLASH芯片,引脚通常很多,而且较为密集,所以对手工焊接造成困难。同时,它也不能被计算机直接读取,需要有相应控制器的配合,所以要将它进行格式化比较困难。

硬盘:常用于计算机中,容量可以非常大。但是它接口较为复杂。其实最不方便的是,它通常需要24V电源供电,使用不便而且很危险。

剩下的就是SD卡与CF卡了。SD卡的优点当然是不言而喻的:易于购买、价格便宜、易于焊接、接口简单、资料齐全等等。(其实这也是众多产品中使用SD卡的原因!)那有人要问:“既然SD卡被选为最佳存储设备,那还要提到CF卡干什么?”这里可以稍带着说一下,对CF卡了解的人可能知道,CF卡的存取速度是比较快的,同时容量也很大,全称是“CompactFlashCard”,俗称是固态硬盘。虽然它的接口针数比较多,但其实我们用单片机驱动它,只用到其中的几根而已,驱动也很简单。所以除了SD卡,我们还选择了CF卡。那么为什么要用到两种存储设备?在这里振南先卖个关子,在后面的章节中,大家自会明白这样作的用意。

下面的讲解,我们还是以SD卡为载体来进行的。

2、SD卡的存储结构我们用SD卡当然是用来存储数据的,文件系统就是用来组织这些数据用的。那么SD卡上的数据是如何存储的呢?数据是一个字节一个字节顺序存储的,可以操作任何一个字节?还是这些字节被组织为基本的数据单元,成块的存储,只能对块进行操作?或者是其它的方式?如图3.2所示,SD卡上的数据存储方式。

图3.2SD卡上的数据存储方式

确切的答案是:SD卡上的数据是以数据块的方式进行存储的。这个数据块我们就称之为扇区!这是一个极为重要的概念。其实不光SD卡是这样,像硬盘、U盘等等这些存储设备中,也是这样来存储数据的。

从图3.2中我们看到一个扇区中包含了若干个字节,通常是512字节,扇区是最基本的读写单位,也就是说,我们不可能单独操作扇区中的某个字节,就算我们要修改扇区中的某个字节,也要把整个扇区都读出来,修改完后再按扇区写回去。可能您会问了,为什么要以扇区为单位,难道按字

节来组织不好吗?扇区这个概念已经延用了几十年,一直至今,这就说明它是科学的,是真正实用的,不然早被淘汰了。让我们来看看为什么要以扇区为基本单元。

①使用扇区来组织数据,适合硬件设计。在硬件的设计与加工工艺水平上,数据以扇区为单位来进行寻址,更容易实现。尤其对于现在超大容量存储芯片的设计与制造上,提供了极大的便利。如果采用字节级的寻址,硬件设计难度会上升,同时,存储设备在容量和性能上也不可能得到今天这样的成就。

②减小寻址的开销。你能想像吗?如果存储设备以字节来寻址,每读取一个字节,都要进行寻址,效率是何其之低!?我们理想的情况是,只需要几次寻址,就可以读到大量的数据。以扇区这种组织方式,每寻到一个扇区,我们就可以读到512个字节,显然很大程度上提高了数据的读取速度。另一方面,对于同样的容量,字节级寻址与扇区级寻址的地址值,后者可能并不算很大,而前者已经是天文数字了。比如我们对一个容量为16M的存储设备进行寻址,如果要寻址到15M位置的数据,扇区地址为30720,而字节地址为157280。也许您觉得这只是一个数值的不同,但因为这点不同,CPU要将地址总线从12位扩展为21位!

③有利于对数据的管理。将数据组织为扇区这种数据块存储的方式,会使文件数据的管理更加方便。在实际的文件

系统应用中,为了更高的效率通常又把若干个扇区组织为簇,关于簇我们在后面将会讲,同时它也是文件系统中极其重要的概念!

关于SD卡其它方面的介绍,如形状、品牌、机械结构等,在这里就不再赘述,因为大多数人都见过SD卡,对它已经比较熟悉,不熟悉的,买张SD卡看看,也就全知道了。

我们对SD卡比较关心的是如果用单片机来读写它的扇区数据?它与单片机的接口是怎样的?这些都是我们在实现FAT32文件系统之前,所必须了解和完成的,而且要保证这些底层操作的稳定性,不能让FAT32文件系统调要它们的时候掉链子。其实我们可以对SD卡的底层扇区读写抽象为FAT32文件系统与底层存储设备驱动的接口。如图3.3,SD卡扇区读写驱动是FAT32的底层接口。

图3.3SD卡扇区读写驱动是FAT32的底层接口

可见,FAT32文件系统并不知道为自己提供底层服务的是SD卡,它只知道是某种存储设备,所以只要我们在我们设计的FAT32文件系统解决方案中提供对底层扇区操作的接口,也就是用于与实际的存储设备驱动相接驳的空函数,就可以极为方便的把FAT32文件系统应用到各种存储设备上(当然这种存储设备要支持FAT32文件系统)。

这里所提出的问题和设计思想在后面的章节中,我们都使它们得以解决及实施。

第二节将SD卡格式化为FAT32我们都知道在我们使用SD卡来存储文件或进行其它文件操作之前,是必须进行格式化的。这就如同在一张白纸上画好表格,我们才知道将内容填到哪里。当然,这个表格的画法就不只一种了。同理,去SD卡卡进行格式化,也有很多种选择,比如把它格式化为FAT16、FAT32或NTFS等等。我们要研究FAT32文件系统,当然要将SD卡格式化为FAT32,这样我们才可以知道在一张文件系统为FAT32的SD卡上的各种文件操作是如何进行的。

1、普通的格式化方法

我们这里准备一张容量为1G的SD卡,并将它格式化为FAT32文件系统。如图3.4,一张容量为1G的SD卡。

图3.4一张容量为1G的SD卡

在Windows中通常有两种格式化方法,详述如下:①使用菜单中的格式化功能

其实这种方法,不用我多说,大家也很熟悉了。但在这里仍要提一下。如图3.5所示,右键菜单中的

格式化。

图3.5右键菜单中的格式化

点击“格式化”后,将会出现格式化对话框,此时我们就可以选择文件系统类型以及进行相关的设置了。如图3.6,格式化SD卡。

图3.6格式化SD卡

②使用命令行格式化

这种方法对Windows的命令行比较熟悉的人,可能会比较常用。其实也是非常实用的。比如我们的计算机受到病毒破坏或其它意外情况,造成右键菜单无法打开,那么就可以用这种方法。

我们使用

+R,可以调出“运行”对话框,或

者直接在“开始”菜单中选择。敲入“cmd”,回车,就可以打开命令行窗口了。如图3.7,Wiindows的命令行窗口。

图3.7Wiindows的命令行窗口

在命令行窗口中输入“formatX:/fs:fat32”,其中X:为SD卡的盘符。如图3.8,使用命令行格式化SD卡。

图3.8使用命令行格式化SD卡

2、将小容量的SD卡格式化为FAT32

上面我们有的是一张容量2G的卡,您可能会问:“我这里没有2G的卡,只有一张32M的卡,行不行?”理论上来说,32M小于FAT32所能支持的最小容量。使用Windows是无法将它格式化为FAT32的,也就是在文件系统的选项中根本就没的FAT32这一项。如图3.9、3.10与3.11。

图3.9一张容量仅有32M的SD卡

图3.10在选项中无FAT32这一项

图3.11命令行中也无法格式化小容量卡

如果无法将小容量卡格式化为FAT32,也就无法在它上面进行文件操作,对FAT32的研究也就无从谈起。真的就没有办法了吗?答案是:否!我们通过一些第三方的软件仍然可以把小容量卡格式化为FAT32。但在Windows中显示的与卡相关的信息可能会有不对的地方,但在卡上进行文件操作是没有问题的,这样就可以省去你买大容量卡的钱了。

我们来看具体的作法:

①运行DiskGenius(DiskMan)软件。如图3.12,DiskGenius的软件界面。

图3.12DiskGenius的软件界面

②找到SD卡相对应的盘符。如图3.13,32MSD卡在DiskGenius中的盘符。

图3.1332MSD卡在DiskGenius中的盘符

③在右键菜单中选择“重建主引导记录(MBR)”(MBR是我们研究FAT32文件系统将要遇到的第一个部分。简要来说,它告诉我们磁盘分区的相关信息,比如分区大小、分区在磁盘中的位置,详细内容我们留到后面来讲解)。如图3.14,右键菜单中的“重建主引导记录”。

图3.14右键菜单中的“重建主引导记录”

④在这张32M的SD卡上新建分区,并对分区参数进行设置。如图3.15,新建分区并设置参数。

图3.15新建分区并设置参数

我们在后面对MBR的讲解中,大家就会看到这些参数,如文件系统类型、分区容量等,都会在其中有所体现。

⑤保存磁盘分区表。振南在刚开始使用DiskGenius的时候,以为新建分区之后就可以直接对其进行格式化了,其实不然,这里还要对磁盘的分区表进行保存。可能因为是上面我们设置的与分区相关的参数还没有真正写入到SD卡中,所以才需要这一步。如图3.16,保存磁盘分区表。

图3.16保存磁盘分区表

⑥对新创建的、但尚未格式化的分区进行格式化,此时需要对一些参数进行设置。如图3.16,对新建的分区进行格式化与设置参数。

图3.16,对新建的分区进行格式化与设置参数

与新建分区时一样,上面设置的参数也会在相应的部分得到体现,这就是研究FAT32文件系统的第二个部分--DBR。其实与文件系统及分区相关的参数信息都会被记录在磁盘上专门的地方,比如上面提到的MBR、DBR,它们到底在磁盘的哪里?我们如何从中读到想要的参数信息?其实这就是我们研究FAT32文件系统将要解决的问题。这些参数就会告诉我们,文件在哪里?目录在哪里?数据在哪里?

到这里,我们已经将一张容量仅有32M的SD卡格式化为FAT32文件系统了。我们前面已经说过,这样一张SD卡,在Windows中是不能直接使用的,为什么不能直接使用,您一看就明白了。如图3.17,在Windows中显示剩余容量为0。

图3.17在Windows中显示剩余容量为0

另外,您可能也已经发现,这张容量为32M的SD卡经过FAT32格式化后磁盘空间仅剩23.3M了,这也是我们在小容量卡上牵强使用FAT32的结果,损失了很多的可能容量。所以小容量的存储设备并不适合用FAT32文件系统,而更适

合于使用低版本的FAT12/16。我们研究FAT32文件系统,主要也是鉴于现在较大容量的存储设备已经成为主流,小容量的存储设备已经慢慢淡出历史舞台了。

总之,使用小容量SD卡来研究FAT32,是我们没有办法时候的下策。其实,您现在想弄到一张小容量SD卡都难了。但也并不是容量越大越好,本书主要围绕一张容量为1G的SD卡来讲解,后面章节中我们实现的SD卡底层驱动最大支持到2G。这是为什么?到后面你自然会明白!

第三节WinHex让SD卡的扇区数据呈现在我们面前我们要想知道FAT32是如何组织SD卡上的存储空间的,它将重要的参数存在了哪里?首先,我们必须要能够很直观的看到它物理扇区中的数据,然后再按照FAT32文件系统协议的描述来对其一点点进行研究。这样就引出了我们研究FAT32的一个极为重要的工具--WinHex。如图3.18,WinHex软件的界面。

图3.18WinHex软件的界面

总得来说,WinHex是一个功能极为强大的软件,但我们现在处于入门阶段,就没有必要去接触那些复杂的功能,我们只要知道两个功能就可以了。

1、打开磁盘设备

要查看磁盘上的扇区数据,就必须先把磁盘打开。WinHex中打开设备有两种方式:逻辑方式与物理方式,这两种方式是全完不同的。简单的说,就是一个是带文件系统解析的,可以帮我们计算出很多文件系统的参数以及进行文件系统级的定位;另一个是不带文件系统解析的,也就是单纯的把物理扇区的数据呈现给我们。完整版的WinHex,是允许我们在扇区中的数据进行修改操作的。也许你还对WinHex中的这两种设备打开方式的不同以及文件系统解析不太了解,这没有关系,在后面的章节中我们会经常用到这个软件,大家也就会对它有更深刻的了解了。如图3.19,WinHex中的两种设备打开方式。

图3.19WinHex中的两种设备打开方式

2、定位扇区

当我们想要查看某一扇区的数据时,我们就可以使用定位扇区功能直接转到相应的扇区。WinHex中的定位扇区功能非常简单。如图3.20,WinHex中的定位扇区功能。

图3.20,WinHex中的定位扇区功能

点击此按钮后,将弹出这样的对话框。如图3.21,扇区定位对话框。

图3.21扇区定位对话框

上图中,将逻辑扇区设置为100,确定之后WinHex就会为我们呈现中磁盘物理扇区号为100的扇区数据。我们定位数据通常

就是使用扇区地址来进行定位,在文件系统中也是这样来作的。其实这个扇区地址,我们在文件系统中应该称其为LBA,即逻辑块地址。它可以使我们在逻辑上认为存储设备的众多存储单元是地址连续的存储空间,而不用关心存储设备是像SD卡或CF卡那样的FLASH结构,还是像硬盘那样的盘片结构。

我们知道了WinHex中的这两个功能的使用方法,我们就可以对磁盘上的具体数据,结合FAT32文件系统协议进行分析研究了。在下一章中,我们就会对MBR(主引导记录)、DBR(DOS引导记录)等部分进行解读,同时大家也会看到振南是如何编程实现的。

振南的znFAT

单片机上的FAT32文件系统----单片机上的

第四章统揽全局三分胜算

上一章中我们详细介绍了几种把SD卡格式化为FAT32文件系统的方法。其实,格式化SD卡的时候,计算机就已经将一些与这张SD卡上的FAT32文件系统相关的参数写到了专门的扇区中了。这些参数是我们进行文件操作的根本依据。比如扇区大小、簇扇区数、根目录首簇等等。由于这些参数极为重要,而且在各种文件操作中都要用到,所以我们称之为全局性重要参数。这些参数基本上把FAT32文件系统整体的轮廓勾画出来了,让我们可以对其有一个全局的认识。

本章会让您看到如何解读这些参数,以及它们的具体作用。同时从这一章开始我们就开始看到代码了,这需要您有一定的C语言基础。好,我们来看详细内容。

第一节解读MBR(主引导记录)1、解析DPT中的记录我们要解读的第一个部分就是MBR(主引导记录)。如果我们照搬FAT32文件系统协议的定义,估计将会使我们的讲述非常无趣。我们的一切研究均从实际出发,所以我们来直接看SD卡的MBR部分的数据,当然我们是用WinHex软件来查看了,这在前面已经讲过。那么MBR在SD卡的哪个扇区呢?这是一个绝对的答案:如果它存在,那么它就一定在0扇区!(这里为什么说“如果它存在”,到后面讲解

DBR的时候您就明白了)如图4.1所示,SD卡的0扇区。

图4.1SD卡的0扇区

上图中我们看到的就是SD卡的0扇区中的数据,也就是所谓的MBR(主引导记录)。那么这些数据表达了怎样的意义呢?这就需要

我们仔细分析了。

这512字节的数据,前面446字节我们不用关心,重点在于图中蓝色标出的字节。这字节其实是4条记录,每条记录是16字节,用来记录SD卡上的分区信息。FAT32文件系统称之为DPT(磁盘分区表)。如图4.2,MBR扇区示意图。

图4.2DBR扇区示意图

我们先取出第一个记录来进行分析:

80:表明这是一个有效的分区。如果这里是00,则说明此分区无效。01:开始磁头。

0100:开始扇区与开始柱面。0B:系统ID。1F:结束磁头。

FFD8:结束扇区与结束柱面。3F000000:分区的开始扇区。A14C1E00:总扇区数。

我们可以看到其实对参数的解析非常简单,FAT32就是把很多参数依次进行存放,我们只需要将这些字节拼在一起就可以得到相应的参数了。比如我们要获得分区的总扇区数,那么我们将这4个字节:A14C1E00拼成一个unsignedlong型的变量,它表达的就是这个参数的值。

解析完第一个记录之后,我们再来看后面的三个记录。它们同样也用来描述分区,如果这张SD卡被分成了多个区,那么后面的记录就会分别记录相应分区相关参数。你可能会问,后面只剩下三个记录了,难道FAT32只支持4个分区?这一点显然与我们实际应用中看到的不相符。我们的磁盘被分为4、5个分区是很常见的事情。其实这是因为有扩展分区的机制在起作用。这部分深入进去也是较为复杂的,我们只研究SD卡上仅有一个分区的情况(其实通常情况下我们很少在SD卡上进行分区,尤其是在嵌入式应用中),所以我们看到后面的记录都是0。

综上所述,我们要解析DPT中的记录,可使用这样的结构体。

structPartRecord{//DPT:分区记录结构如下UINT8Active;UINT8StartHead;//0x80表示此分区有效//分区的开始磁头UINT8StartCylSect[2];//开始柱面与扇区UINT8PartType;UINT8EndHead;//分区类型//分区的结束头UINT8EndCylSect[2];//结束柱面与扇区UINT8StartLBA[4];UINT8Size[4];};当然,MBR的结构体我们也可以轻松得到。

//分区的第一个扇区//分区的大小structPartSector{UINT8PartCode[446];//MBR的引导程序structPartRecordPart[4];//4个分区记录UINT8BootSectSig0;//0x55UINT8BootSectSig1;//0xAA};到后面,我们就可以看到znFAT中是如何使用这些结构体来进行相关参数的计算和提取的。

2、“大端”与“小端”(Big-Endian与Little-Endian)在讲解什么是“大端”与“小端”前,让振南先给您讲一个故事,

这也是这两个名词的来历。

Endian这个词来源于JonathanSwift在1726年写的讽刺小说“Gulliver‘sTravels”(《格利佛游记》)。该小说在描述Gulliver畅游小人国时碰到了如下的一个场景。在小人国里的小人因为非常小(身高6英寸)所以总是碰到一些意想不到的问题。有一次因为对水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开的争论而引发了一场战争,并形成了两支截然对立的队伍:支持从Big-End剥开的人Swift就称作Big-Endians而支持从Little-End剥开的人就称作Little-Endians(后缀ian表明的就是支持某种观点的人)。Endian这个词由此而来。

为什么要引出这样的两个名词,往后看您就会明白了。

其实细心的读者已经发现了一些问题。上面获取分区总扇区数的例子中,将A14C1E00拼为一个unsignedlong型的变量,即0xa14c1e00=2706120192,也就是说这张容量为1G的SD卡上唯一的分区总扇区数为2706120192,这样算出来的容量为1290G。这是怎么回事,起码这个值要与1G差不多?!其实这里在计算上我们犯了一个错误,从根本上来讲,也不能算是错误,只是因为FAT32文件系统中的参数字节排列顺序与单片机上不同。这也就是所谓的“大端小端”问题。

我们举例来说:拿一个unsignedlong型的变量来说,如果它的值为0x12345678,那么构成这个变量的4个字节的值分别为0x12、0x34、0x56、0x78。这个变量必然被存储在内存之中,那么不同的CPU,在

存储方式上有所不同。如果是在PC上(PC上的CPU,通常是CISC的,为小端模式),那么这个变量的最高字节0x12被存储在高地址上,最低字节0x78被存储在低地址上,最终排列为0x780x560x340x12;而如果是在51上(单片机的内核CPU通常是RISC的,为大端模式),则截然相反,排列为0x120x340x560x78。当然,如果将大端与小端混淆了,就会使变量的值大相径庭。

这里要点明的是,FAT32文件系统最初为PC设计,所以它遵循小端模式的存储规则。上面的总扇区数其实应该是0x001e4ca1=1985697,也就是SD卡的分区容量约为977M,也就是10166768字节。让我们看看是不是与WinHex分析的相吻合(WinHex以逻辑方式打开磁盘,就可以对磁盘进行文件系统级的分析)。如图4.2,WinHex分析得到的总容量。

图4.2WinHex分析得到的总容量

可以看到,我们计算的结果与WinHex分析的结果是完全吻合的。这说明我们的理解是正确的。在后面对参数的计算中也同样采用这种方式。因此,我们有必要写一个函数,用来把小端转为大端。

UINT32LE2BE(UINT8*dat,UINT8len){,fact=1;UINT32temp=0temp=0,UINT8i=0;for(i=0;i图4.4SD卡的DBR扇区

上面就是SD卡的DBR扇区数据,其中蓝色标记的部分就是BPB(79字节)。很多重要的参数都记录在其中。到底都有哪些参数,它们分别占用了哪些字节,我们来看这样一张图。图4.5,DBR扇区示意图。

图4.5DBR扇区示意图

可以看到,BPB中的参数比DPT中要复杂得多,这是因为绝大部分的全局重要参数都在这里,所以BPB是极为重要的。对BPB的解析是否正确,直接关系到FAT32文件系统实现成功与否。

我们依照图中的标注及WinHex中得到的DBR扇区数据来仔细分析一下这些参数。

0002:每扇区的字节数(0x0200=512)08:每簇扇区数(0x08=8)2000:保留扇区数(0x0020=32)02:FAT表数(0x02=2)0000:FAT32固定为00000:FAT32固定为0F8:存储介质类型

0000:FAT32固定为03F00:磁道扇区数00FF:磁头数

3F000000:FAT区前隐扇区数(0x0000003F=63)A14C1E00:总扇区数(0x001E4CA1=1985697)90070000:FAT表所占扇区数(0x00000790=1936)0000:FAT32特有0000:FAT32特有

02000000:第一个目录的簇号(0x00000002=2)0100:FSINFO扇区数0600:通常为612个00:用于扩展00:驱动器号00:保留29:扩展引导标签7A160E90:分区序列

4E4F204E414D4520202020:卷标413332202020:系统ID

按照上面的定义,我们可以构造出这样一个结构体了(结构体中除了BPB部分,还包含了前面的一小段数据,这是为了便于数据解析)。

structFAT32_BPB//FAT32中对BPB的定义如下{UINT8BS_jmpBoot[3];UINT8BS_OEMName[8];//跳转指令//UINT8BPB_BytesPerSec[2];//每扇区字节数UINT8BPB_SecPerClus[1];//每簇扇区数UINT8BPB_RsvdSecCnt[2];//保留扇区数目UINT8BPB_NumFATs[1];//此卷中FAT表数UINT8BPB_RootEntCnt[2];//FAT32为0UINT8BPB_TotSec16[2];UINT8BPB_Media[1];UINT8BPB_FATSz16[2];UINT8BPB_SecPerTrk[2];//FAT32为0//存储介质//FAT32为0//磁道扇区数UINT8BPB_NumHeads[2];//磁头数UINT8BPB_HiddSec[4];UINT8BPB_TotSec32[4];UINT8BPB_FATSz32[4];UINT8BPB_ExtFlags[2];UINT8BPB_FSVer[2];UINT8BPB_RootClus[4];UINT8FSInfo[2];//FAT区前隐扇区数//该卷总扇区数//一个FAT表扇区数//FAT32特有//FAT32特有//根目录簇号//保留扇区FSINFO扇区数UINT8BPB_BkBootSec[2];//通常为6UINT8BPB_Reserved[12];//扩展用UINT8BS_DrvNum[1];UINT8BS_Reserved1[1];UINT8BS_BootSig[1];UINT8BS_VolID[4];UINT8BS_FilSysType[11];UINT8BS_FilSysType1[8];};看了上面的参数解析,你一定会说:“BPB中的参数确实是太复杂了!”。表面上来看是这样的,这也是初学FAT32文件系统不好入门的地方,刚开始就被繁多的参数阻拦,使我们无法前行,但如果你了解了这些参数是用来作什么的,对FAT32文件系统有什么意义之后,就会觉得思路畅通,水到渠成了。

参数虽多,但实际上并不是每一个我们都用得到的,我们需要将那些重要的参数提取出来。

0002:每扇区的字节数(0x0200=512)08:每簇扇区数(0x08=8)2000:保留扇区数(0x0020=32)02:FAT表数(0x02=2)

90070000:FAT表所占扇区数(0x00000790=1936)02000000:第一个目录的簇号(0x00000002=2)

为什么单单把这几个参数提出来?在了解了FAT32文件系统的整体结构之后,您就明白了!

其实相信很多人在看本节的时候心里一直带着一个疑问:DBR扇区在哪里?仔细看了第一节的人就会知道,MBR中的DPT中有一个字段叫作“分区的第一个扇区”,它就是所谓的DBR了(该字段为3F000000,计算得到的值为63,即MBR在63扇区)。但如果您有印象,我们还说过一句话“如果MBR存在,那么它在0扇区”,言外之意是MBR是有可能不存在的(MBR存在与否决定于格式化软件)。如果MBR不存在,那么0扇区就是DBR,而判断的依据就是扇区数据的第一个字节是否是0xEB。

所以在定位DBR时,程序在处理上就要更灵活一些,以下就是znFAT中定位DBR的函数。

UINT32FAT32_Find_DBR(){UINT32sec_dbr;FAT32_ReadSector(0,FAT32_Buffer);//读0扇区到缓冲区if(FAT32_Buffer[0]!=0xeb)//如果缓冲区第一个字节不是0xeb,说明MBR存在{sec_dbr=LE2BE(((((structPartSector*)(FAT32_Buffer))->Part[0]).StartLBA),4);//从MBR的DPT中解析出DBR的扇区地址}else{sec_dbr=0;//否则说明MBR不存在,0扇区就是DBR}returnsec_dbr;//返回DBR所在的扇区地址}在这段程序中,我们可以看到它使用了上面我们定义的MBR的结构体,采用指针的强制类型转换的方法直接定位到分区开始扇区的字节序列,并调用LE2BE函数将其转为大端模式,最终得到实际的值。这种对扇区数据的某些字段进行解析提取的方法,我们在后面的程序中会经常见到,如果您在理解上仍有困难,请翻阅C语言的相关教程,先把C语言学扎实!

另外就是FAT32_ReadSector这个函数也是第一次出现,顾名思义,它用来读取存储设备的扇区。与FAT32_WriteSector一起构成了znFAT的底层存储设备驱动接口。如图4.6,znFAT的底层存储设备驱动接口。

图4.6znFAT的底层存储设备驱动接口

这两个函数其实是两个空壳,需要根据具体的存储设备进行编写,这也就使得znFAT可以适用于很多的存储设备,比如SD卡、CF

卡、MS卡等等。下面就是以SD卡为设备存储的底层接口函数的具体实现。

UINT8FAT32_ReadSector(UINT32addr,UINT8*buf){returnSD_Read_Sector(addr,buf);//SD卡扇区读函数}UINT8FAT32_WriteSector(UINT32addr,UINT8*buf){returnSD_Write_Sector(addr,buf);//SD卡扇区写函数}可以看到这两个函数的实现是很简单的,都是直接调用存储设备的扇区读写函数(关于SD卡驱动方法我们在后面会有专门章节进行讲解)。到了后面,我们在这个底层接口上会翻出更多花样,从而使znFAT实现多设备功能,此为后话,暂且不提。

4、对FAT32文件系统各部分的定位解析全局参数的目的在于对FAT32各部分进行定位,比如前面讲到的MBR、DBR,再如后面将要讲到的FAT表、首目录簇等。对各部分在SD卡上的位置进行准确定位,意义是极其重大的。想像一下,我们连根目录都找不到,又何谈对操作文件呢?连FAT表在哪里都不晓得,怎能知道文件数据的分布情况?此时,我们有必要对FAT32文件系统的整体结构有一个了解了,随后我们再用上面我们提取出来的

参数来计算这些部分的具体位置。我们先来看这样一张图,图4.7,FAT32整体结构。

图4.7FAT32整体结构

对图中各个部分的具体功能和定义我们会在专门的章节进行讲解,这里我们要作的是计算它们的具体位置,也就是它们分别从哪个扇区开始,到哪个扇区结束。

MBR与DBR就不用说了。DBR后面是保留区,我们提取出来的参数中有保留扇区数,值为32。这说明这部分占用了32个扇区。再后面就是第一个FAT表,它占用了1936个扇区,这样可以轻松计算得到第一个FAT表以及紧随其后的第二个FAT表的开始扇区。

第一个FAT表开始扇区=DBR扇区+保留扇区数(95)第二个FAT表开始扇区=第一个FAT表开始扇区+FAT表所占扇区数(2031)最后是首目录簇(通常是第2簇),它是我们访问任何文件或目录的入口,也就是平常所说的根目录!而且从这里开始后面的数据都以“簇”为单位(簇的概念会在后面讲到,它也是极为重要的,这里只需要知道簇是由若干扇区组成的即可),在其之前,数据都以扇区为单位。那么首目录簇的开始扇区如何计算呢?其实道理是一样的。

首目录簇的开始扇区=第一个FAT表的开始扇区+2*FAT表所占扇区数(3967)其实得到了首目录簇,即第2簇的开始扇区,我们也就知道了任何一个簇的开始扇区。

第n簇开始扇区=(n-首目录簇)*簇所占扇区数+首目录簇开始扇区我们来看一下我们解析计算出来的参数值是否与WinHex中相吻合。如图4.8,WinHex中首目录簇的开始扇区。

图4.8WinHex中首目录簇的开始扇区

图中WinHex中的首目录簇的开始扇区为3967(在逻辑方式下,逻辑扇区是以DBR所在扇区为0扇区的,所以与物理扇区相差63),这与我们算出来的值是一致的,说明我们的理解是正确的。

这样,我们就已经知道这张SD卡的FAT32文件系统的各个部分的准确位置的了,再加上前面解析出来的一些参数,它们在我们后面的程序中都会被经常用到,所以我们构造出这样一个结构体,用来装载这些信息,在文件系统的运行周期内,结构体内数据都是一直存在的。

structFAT32_Init_Arg{UINT8BPB_Sector_No;//BPB所在扇区号UINT32FirstDirClust;//首目录簇UINT32BytesPerSector;//每个扇区的字节数UINT32FATsectors;//FAT表所占扇区数UINT32SectorsPerClust;//每簇的扇区数UINT32FirstFATSector;//第一个FAT表开始扇区UINT32FirstDirSector;//首目录簇开始扇区};下面我们就通过这个函数装参数装入到这个结构体中。

voidFAT32_Init(){structFAT32_BPB*bpb;bpb=(structFAT32_BPB*)(FAT32_Buffer);//将数据缓冲区指针转为structFAT32_BPB型指针pArg->BPB_Sector_No=FAT32_Find_DBR();//FAT32_FindBPB()可以返回BPB所在的扇区号pArg->FATsectors=LE2BE((bpb->BPB_FATSz32),4);//装入FAT表占用的扇区数到FATsectors中pArg->FirstDirClust=LE2BE((bpb->BPB_RootClus),4);//装入根目录簇号到FirstDirClust中pArg->BytesPerSector=LE2BE((bpb->BPB_BytesPerSec),2);//装入每扇区字节数到BytesPerSector中pArg->SectorsPerClust=LE2BE((bpb->BPB_SecPerClus),1);//装入每簇扇区数到SectorsPerClust中pArg->FirstFATSector=LE2BE((bpb->BPB_RsvdSecCnt),2)+pArg->BPB_Sector_No;//装入第一个FAT表扇区号到FirstFATSector中pArg->FirstDirSector=(pArg->FirstFATSector)+(bpb->BPB_NumFATs[0])*(pArg->FATsectors);//装入第一个目录扇区到FirstDirSector中}这个函数就是znFAT的第一个应用接口函数----文件系统初始化。现在,这只用来装载文件系统相关参数,在后面我们将对其进行扩展,加入更多的变量,比如为了实现多设备功能而加入的设备号,来源于FSInfo的新簇参考值等等。

本章到此将尽,我们已经了解了FAT32文件系统的大概轮廓,知道了各个部分位置的计算方法。然而这些部分是用来作什么的?它们具体的定义是怎样的?这些都是后面我们要讲解的内容。

在下章中,我们将会在SD卡上拷入一个TXT文本文件,振南会告诉你如果找到这个文件的数据以及解析出这个文件的相关信息。

振南的znFAT

--单片机上的FAT32文件系统--单片机上的

第五章文件目录寻踪

在上一章中我们已解析出了大量参数,最终我们由这些参数计算得到了FAT32各功能部分的具体位置。在本章中,我们将以实例方式详细向您介绍在SD卡上对文件目录进行操作时,这些功能部分都充当怎样的角色。

在本章实例中,我们将用计算机在SD卡根目录下创建一个名为ZNMCU.TXT的文本文件,并向其中敲入一些字符。我们要作的就是找到该文件及其数据,并用单片机予以实现。当然我们在实现这一实例的同时,也会讲解很多相关内容,甚至将实例进行深化,一来使我们的知识和思维得到拓展,二来为我们后面的学习作好铺垫。闲话少说,我们进入正文。1、定位文件目录项

在计算机上在SD卡根目录下创建文件,想必人人都会,不用多说。如图5.1所示,SD卡根目录下的ZNMCU.TXT文件。

图5.1D卡根目录下的ZNMCU.TXT文件

在Windows等操作系统中我们当然可以很轻易看到这个文件,并打开它查看其内容。而我们现在要作的是,根据前面我们计算得到的参数,使用WinHex软件找到这个文件及其数据所在扇区(更准确得说是“簇”,在后面会专门讲到它的概念)。

这个ZNMCU.TXT文件在SD卡的根目录下,所谓的根目录,在FAT32中更准确的说其实就是首目录,即第一个目录,用意在于说明它与其它的目录是一样的,没有什么特殊之处(关于这一点,您到后面会有更深的感受)。好,既然知道这个文件在首目录下,而我们也已经计算得到了首目录簇的开始扇区(3967扇区),那么我们就用WinHex打开这个扇区,看看它的数据是怎样的。如图5.2,SD卡的3967扇区数据。

图5.2SD卡的3967扇区数据

图中横线标出的部分就是ZNMCU.TXT文件的文件目录项,一共是32个字节。这32个字节就描述了与该文件相关的大部分信息,如文件名、文件创建时间、访问时间、文件大小、文件数据的位置等等。现在看起来似乎是一堆零乱的字节,经过下面的解析之后,它就会露出它庐山新面目了。

2、解析文件目录项

我们把上面的文件目录项单独拿出来,如图5.3,ZNMCU.TXT文件的文件目录项。

图5.3ZNMCU.TXT文件的文件目录项

结合文件目录项的结构定义,如图5.4,文件目录项的结构定义。

图5.4文件目录项的结构定义

将这32个字节的文件目录项划分为若干字段,并可知道各字段的意义。

5A4E4D4355202020:ZNMCUZNMCU 58:TXT扩展名20:文件属性为归档00:系统保留

文件名

79:创建时间10毫秒位121(十毫秒),即1.21秒C06B:文件创建时间13:30:00

563B:文件创建日期2009年10月22日563B:文件访问日期2009年10月22日0000:文件开始簇号的高16位0000BB6B:最近修改时间13:29:563B:最近修改日期2009.10.220300:文件开始簇号的低16位000333000000:文件长度51

看了上面对这些字段定义的描述,我们已经大体了解了它们是作什么用的了。每一个条目后面是我们解析出来的内容与参数,先来看看这些信息是否与Windows中读出的相一致。如图5.4,ZNMCU.TXT在Windows中读出的信息。

图5.5ZNMCU.TXT在Windows中读出的信息

当然像文件的首簇、10毫秒位这些参数我们在Windows的“文件属性”是看不到的(在WinHex中可以看到)。可以看到,上图中的内容与上面我们解析的结果是完全一致。这说明对文件信息的解析是正确的。那么这些信息该如何从这32个字节中解析出来呢?这就需要细细来进行讲解了。

1)文件名

说到FAT32中的文件名,它的名堂很多,甚至会涉及到一些不公开的算法。其实仔细想想,这也不奇怪。从文件系统出现的那一天起,我们访问文件,大多还是通过文件名来访问的,可以说,文件名与文件本体构成了最为直接的映射关系。久而久之,因为实际应用的各种需求,文件名也就变得越来越复杂。到底文件名诸多名堂出于何处,复杂的文件名是什么样子,到后面您就会有深刻的认识了。这里我们先来看看最基础,最简单的8.3短文件名是怎样的。

所谓的8.3短文件名就是文件名为8个字符,扩展名为3个字符,如上例中的ZNMCU.TXT。文件名部分如果不足8个字符则用空格补齐,扩展名部分同理。所以ZNMCU.TXT这个文件名在文件目录项中的表示就是:

5A4E4D435520202058

我们再多举几个例子:

ABCDEFGH.MP3:4142434447484D5033ABC.X:41424320202020205820201234.123:3132333420202020313233

可能您已经发现了一些问题,为什么文件名里的英文字符都是大写

的?没错,FAT32文件系统中8.3短文件名中的字符只有大写,没有小写。您紧接着一定会问:“这不对啊,我经常看到小写文件名,这是怎么回事?”我要说,您看到的小写文件名,已经属于“长文件名”范畴,这也正是前面我们说到的文件名的复杂之处之一(您只要记住,凡是8.3短文件名不能解决的问题,大多都是由长文件名来解决的)。

但此时,我们脑中会产生一个很大的困惑,那就是,如果SD卡中一个以小写字符命名的文件,我们如何来访问它。这就要说到FAT32中文件名的兼容性设计。说白了,就是一个具有长文件名的文件,它同样也具有相应的8.3短文件名,以方便在某些不支持长文件名的系统中对其进行访问。我们以下例来进行说明。

1.在SD卡上根目录下建立一个文件,命名为abcdefghijk.txt。如图5.5,SD卡上的abcdefghijk.txt文件。

图5.6SD卡上的abcdefghijk.txt文件

2.用WinHex查看根目录下的文件目录项。如图5.6,SD卡根目录下的文件目录项。

图5.7SD卡根目录下的文件目录项

从上图中可以看到,abcdefghijk.txt这个文件有一个8.3短文件名,

即ABCDEF~1.TXT。这种表达方式想必很多人看起来眼熟。对!在古老的DOS里,对于过长的文件名就是这样表达的。它是最典型的不支持长文件名的系统(在今天我们使用的系统中,大多数是支持长文件名的,所以这种表达方法已经很少见到了)。图中8.3文件目录项上面的数据用于表达长文件名,这个我们放到后面章节再来细究。

这样,每一个文件起码会有一个标准的8.3短文件名,通过它我们照样可以访问到文件。2)文件属性

文件的属性用文件目录项中的一个字节来进行表达,所以它是较为简单的。这个字节的每一个位为1还是为0,表示文件是否具有某种属性。如上例中,文件属性为归档,该字节为0x20(第四个位表示是否归档)。如图5.7,属性字节各位的意义。

图5.8属性字节各位的意义

这些属性是可以迭加的,比如某个文件的属性为“归档、隐藏”,那么它的属性字节值为0x22。

好,既然文件的属性仅由这一个字节决定,那么是不是我们手动的

修改这一字节的值就可以修改文件属性呢?我们来作个实验。

ZNMCU.TXT这个文件的属性为归档,我们使用WinHex修改它的属性字节为0x03,即属性为“只读、隐藏”。如图5.9所示,手动修改文件属性字节。

图5.9手动修改文件属性字节

此时,我们再在Windows中看看ZNMCU.TXT文件的属性。如图5.10,属性字节修改后的文件属性。

图5.10属性字节修改后的文件属性

从上图中可以看到,文件的属性确实按照我们的意思已经改为“只读、隐藏”了,说明我们的理解是正确的。

3)文件的创建时间

文件的创建时间在很多实际的应用中都是很重要的。举个例子,一个数据采集系统,每天新建一个文件用来记录当天的数据。一年后,面对365个文件,如果文件没有创建时间,你又该如何调出某一天的数据呢?当然,如果您的应用中,对时间并不关心,知不知道文件创建时间无所谓,它意义可能你就感觉不到了。但znFAT作为一种完备的应用方案,必须要考虑到这一点。也就是说,通过znFAT必须要能够获取到某个文件的时间信息(不光是创建时间,还有稍后要讲到的访问时间、修改时间等);在znFAT创建文件时,必须能够通过某种途径或接口获取当前实际时间,并更新到文件目录项中。当然这些是后面的内容,我们在这里如蜻蜓点水般提一下,让您有一个印象。

我们来看看是如何从文件目录项中解析出文件的创建时间的(这里所说的时间包括时间与日期,把它们放在一起来讲)。先取出ZNMCU.TXT的文件目录项中表示创建时间的两个字节,如下:

C06B:文件创建时间13:30:00

可能你怎么看这两个字节也表达不出13:30:00,让我解析给你看。如图5.11,文件创建时间的解析方法。

图5.11文件创建时间的解析方法

是不是很简单?同时,你是不是已经感觉到FAT32设计的巧妙了呢?不过这里有一个需要注意的地方,那就是秒位的单位为2秒,也就

是说如果秒位为00001,那么实际表达的值为2秒。问题在于这个奇怪的单位,而在于这样一来,岂不是不能表达奇数秒了,比如3秒、5秒等。

其实我们忽略了一点,那就是10毫秒位,如下:

79:创建时间10毫秒位121(十毫秒),即1.21秒

这样一来,我们就得到了实际的创建时间,即13:30:01,这与前面Windows中解析的结果是一致的。

接下来是文件的创建日期,如下:

563B:文件创建日期2009年10月22日

对其进行解析,其实道理是相同的,如图5.12,文件创建日期的解析方法。

图5.12文件创建日期的解析方法

上图中解析的结果,又有一点小问题,年为何是29?这涉及到FAT32文件系统中对文件日期的约定,年+1980才是实际的年份。所以,文件创建日期应该为2009年10月22日,这也与Windows的解析结果是一致的。

另外,从这一点,我们也可以了解到FAT32文件系统的有效期,即在理论上到0b1111111(127)+1980=2017年以前,FAT32文件系统是有效的。但想必在没有到2017年以前,一种更适合发展趋势的,更加优秀的文件系统便会取而代之。但在很长的一段时间内,FAT32文件系统

将仍然是主流,所以我们研究它是很有意义的。4)其它时间信息

除了文件的创建时间与日期,还有其它的一些时间信息,如修改时间、访问时间等。其实解析它们与上面的解析方法是一样的,这里我就不再赘述了。

需要注意的是,对于访问时间,在FAT32文件系统只定义了日期,而没有定义时间,所以在前面图5.10中的访问时间一项中我们只能看到日期,而看不到时间。5)文件大小

文件大小是用来表示文件实际有效数据的字节数的,为什么说“有效数据”呢?我们举个例子,我们向一个文件中添加一些数据,如果我们不更新文件目录项中的文件大小的话,那么我们在Windows等操作系统中查看文件时,你会发现看不到新添加的数据,也就是说在更新文件大小前,这些数据就是无效的,并不纳入文件之中。这是我们后面编写znFAT时将要注意的问题。

而且,文件大小是我们读取文件数据的重要依据。比如,如果我们要从一个大小为50字节的文件中读取100个字节的数据,这显然超出了文件的范围,需要作特殊的处理(具体的处理方法,我们在后面将进行详细讲解)。

说了这么多,我们来看看文件大小的解析,如下:

33000000:文件长度51

可能您已经看出来了,只要将33000000由小端转为大端就得到

结果了。6)文件首簇

通过文件首簇,我们就可以找到文件的数据了。读写文件数据是我们进行文件操作的核心要务,文件首簇告诉我们文件的数据从何处开始,所以正确的解析文件首簇是极为重要的。文件首簇是由两个字段拼接而成的,我们把它提出来,如下:

0000:文件开始簇号的高16位00000300:文件开始簇号的低16位0003

解析方法如图5.13,文件首簇的解析方法。

图5.13文件首簇的解析方法

这样,解析出来的结果是第3簇,即文件的数据是从第3簇开始的。为什么是第3簇?仔细想想这是有科学道理的。前面我们已经说了,根目录(首目录)在第2簇,它用来记录文件目录项(我们获得的ZNMCU.TXT的文件目录项就是从第2簇的首扇区中得到的),已经被占用。此时,ZNMCU.TXT的数据将被分配到除第2簇以外的某一个簇上去。由就近的原则,于是第3簇便成为了文件首簇。

现在,我们可以用WinHex打开第3簇来看看文件的数据是不是真的在这里。你在问什么?“第3簇是哪个扇区?”。还记得吗,第四章中讲到的第n簇开始扇区的计算方法(可不要看了后面的,忘了前面

的,知识要连贯)。如下:

3-2)*8+3967=3975第3簇开始扇区=(=(3)*8我们用WinHex打开SD卡的3975扇区,如图5.14,SD卡3975扇区数据。

图5.14SD卡3975扇区数据

从上图中,我们可以看到,这里的数据正是我们向ZNMCU.TXT文件中敲入的内容。我们已经成功找到文件的数据了!

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- sceh.cn 版权所有 湘ICP备2023017654号-4

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务