FAT文件系统的概况图

1、MBR
进行百度得到,计算机在按下power键以后,开始执行主板bios程序。进行完一系列检测和配置以后。开始按bios中设定的系统引导顺序引导系统。假定现在是硬盘。Bios执行完自己的程序后如何 把执行权交给硬盘呢。交给硬盘后又执行存储在哪里的程序呢。其实,称为mbr的一段代码起着举足轻重的作用。MBR(masterboot record),即主引导记录,有时也称主引导扇区。位于整个硬盘的 0 柱面 0磁头 1 扇区(可以看作是硬盘的第一个扇区),bios在执行自己固有的程序以后就会jump到mbr中的第一条指令。将系统的控制权交由mbr来执行。在总共512byte的主引导记录中,MBR的引导程序占了其中的前 446 个字节(偏移 0H~偏移 1BDH),随后的 64 个字节(偏移 1BEH~偏移 1FDH)为DPT(DiskPartitionTable,硬盘分区表),最后的两个字节“55 AA”(偏移 1FEH~偏移1FFH)是分区有效结束标志。但是如果是裸机的话,前面的446个字节的引导就无所谓了

2、DBR
用于记录分区的一些信息,例如:

【1】0x00~0x02:3 个字节,跳转指令。
【2】0x03~0x0A:8 个字节,文件系统标志和版本号,这里为 MSDOC5.0。
【3】0x0B~0x0C:2 个字节,每扇区字节数,512(0X02 00)。
【4】0x0D~0x0D:1 个字节,每簇扇区数,8(0x08)。
【5】0x0E~0x0F:2 个字节,保留扇区数,704(0x02 C0)。
【6】0x10~0x10:1 个字节,FAT 表个数,2。
【7】0x11~0x12:2 个字节,根目录最多可容纳的目录项数,FAT12/16 通常为 512。FAT32 不使用此处值,置 0。
【8】0x13~0x14:2 个字节,扇区总数,小于 32MB 时使用该处存放。超过 32MB 时使用偏移 0x20~0x23 字
节处的 4 字节存放。笔者的 SD 卡容量为 2GB,所以不使用该处,置 0.
【9】0x15~0x15:1 个字节,介质描述符,0xF8 表示本地硬盘。
【10】0x16~0x17:2 个字节,每个 FAT 表的大小扇区数(FAT12/16 使用,FAT32 不使用此处,置 0)。
【11】0x18~0x19:2 个字节,每磁道扇区数,63(0x00 3F)。
【12】0x1A~0x1B:2 个字节磁头数,255(0x00 FF)。
【13】0x1C~0x1F:4 个字节,分区前已使用扇区数,137(0x00 00 00 89)
【14】0x20~0x23:4 个字节,文件系统大小扇区数,3841911(0x 00 3A 9F 77)。
【15】0x24~0x27:4 个字节,每个 FAT 表的大小扇区数,3744(0x 00 00 0E A0)。
【16】0x28~0x29:2 个字节,标记。
【17】0x2A~0x2B:2 个字节,版本号。
【18】0x2C~0x2F:4 个字节,根目录簇号,2。(虽然在 FAT32 文件系统下,根目录可以存放在数据区的任
何位置,但是通常情况下还是起始于 2 号簇)
【19】0x30~0x31:2 个字节,FSINFO(文件系统信息扇区)扇区号,1。(上图的标注即用黄色条纹的标注
有误,请读者注意)该扇区为操作系统提供关于空簇总数及下一可用簇的信息。
【20】0x32~0x33:2 个字节,备份引导扇区的位置,6。(上图的标注即用黄色条纹的标注有误,请读者注
意)备份引导扇区总是位于文件系统的 6 号扇区。
【21】0x34~0x3F:12 个字节,未使用。
【22】0x40~0x40:1 个字节,BIOS INT 13H 设备号,0x80。(这个我也不知道什么意思☺)
【23】0x41~0x41:1 个字节,未用。
【24】0x42~0x42:1 个字节,扩展引导标志。0x29。
【25】0x43~0x46:1 个字节,卷序列号。通常为一个随机值。
【26】0x47~0x51:11 个字节,卷标(ASCII 码),如果建立文件系统的时候指定了卷标,会保存在此。笔
者当时没有指定卷表,上图中的 YCY 是后来指定的。
【27】0x52~0x59:8 个字节,文件系统格式的 ASCII 码,FAT32。
【28】0x5A~0x1FD:410 个字节,未使用。该部分没有明确的用途。
【29】0x1FE~0x1FF:签名标志“55 AA”。

static U8 BPB_Data [BytesPerSector]={0xeb,0x3c,0x90,//偏移0:相当于JUMP 0X3C 语句,表明系统引导代码在0X3C+2=0X3F处,在FAT32时要改为EB5890'L','F','A','T','V','1','.','0',///偏移3:厂家代码LOWBYTE(BytesPerSector),HIGHBYTE(BytesPerSector),  //偏移11: 每个扇区的大小,这里为512个字节,SectorPerClus,//偏移13,                              LOWBYTE(RSD_Sector),HIGHBYTE(RSD_Sector),//偏移14FAT_NUM,//偏移16LOWBYTE(Directory_Number),HIGHBYTE(Directory_Number),//偏移170,0,//偏移19:小扇区才用,大于16位的扇区数不用LOWBYTE(Total_Sector),HIGHBYTE(Total_Sector),0xf8,0,0,//偏移22:LOWBYTE(Fat_Sector_Num),HIGHBYTE(Fat_Sector_Num),//偏移每个FAT表占的字节数,对于FAT32为00x00,0x00,// 偏移24:每个磁道扇区数0x00,0x00,//偏移24:磁头数0x01,0x00,0x00,0x00,//偏移28:FAT表前的隐藏扇区数,一般不使用LOWBYTE(Total_Sector),HIGHBYTE(Total_Sector),HIGH_LOWBYTE(Total_Sector),HIGH_HIGHBYTE(Total_Sector),//0x00,0x00,0x00,0x00,// 偏移32:大扇区总扇区数,FAT32为非零//This field is the new 32-bit total count of sectors on the  ////对于FAT32,下面4个字节为FAT扇区数                                      LOWBYTE(Fat_Sector_Num),//0x00,//偏移:36  驱动器号,软盘为0HIGHBYTE(Fat_Sector_Num),//0x00,//偏移:37    保留HIGH_LOWBYTE(Fat_Sector_Num),//0x29,//偏移:38   扩展引导记录0X29,指示后三项可用HIGH_HIGHBYTE(Fat_Sector_Num),//'N',LOWBYTE(Fat_BeginClust),HIGHBYTE(Fat_BeginClust),HIGH_LOWBYTE(Fat_BeginClust),HIGH_HIGHBYTE(Fat_BeginClust),//偏移:40 FAT32的扩展标志和文件系统版本,这里用作FAT起始簇号LOWBYTE(Fat_BeginClust1),HIGHBYTE(Fat_BeginClust1),HIGH_LOWBYTE(Fat_BeginClust1),HIGH_HIGHBYTE(Fat_BeginClust1),//偏移:44 LOWBYTE(Directory_BeginClust),HIGHBYTE(Directory_BeginClust),HIGH_LOWBYTE(Directory_BeginClust),HIGH_HIGHBYTE(Directory_BeginClust),//偏移:48 在FAT32中用于根目录起始簇号一般固为2,这里借用它,但是是浮动的LOWBYTE(Directory_BeginClust1),HIGHBYTE(Directory_BeginClust1),HIGH_LOWBYTE(Directory_BeginClust1),HIGH_HIGHBYTE(Directory_BeginClust1),//偏移:52   在FAT32中用于根目录起始簇号一般固为2,这里借用它,但是是浮动的'J','F','A','T','1','6',//偏移:56   FAT12,FAT16,FAT32标志//Executable Code//引导代码0,0,0,0,0,        0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,  0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,0,      0,0,0,0,//DPT硬盘分区表0x00,//0X1BE//active partion0x00,//head0x00,//partion begin0x00,//cylinder0x06,//is partion used//分区类型标志,FAT16=0X060x00,//end head0x00,//partion end 0x00,//end cylinder0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,//fist partion//扇区总数0,0,0,0,0,       0,0,0,0,0,      0,0,0,0,0,      0,//second partion0,0,0,0,0,        0,0,0,0,0,      0,0,0,0,0,      0,//third partion0,0,0,0,0,     0,0,0,0,0,      0,0,0,0,0,      0,//forth partion0x55,0xAA  // Offset_U16_Signature     510 //0x55AA           }

3、FAT表:
这个表是用来对簇的管理,标志磁盘上的簇号是否已经是用过的了。并具有指向下一个簇号的功能
我们现在来尝试读取起始于 3 号簇的文件:
第一步:由该文件的目录项中得知它的第一簇存储在 3 号簇,到 3 号簇读取它的内容后,查看 3 号 FAT 表
项。
第二步:3 号表项内的表项值为 4,即存储文件的下一个簇为 4 号簇,读取 4 号簇中的内容,查看 4 号簇对
应的 4 号 FAT 表项。
第三步:4 号表项内的表项值为 5,即存储文件的下一个簇为 5 号簇,读取 5 号簇中的内容,查看 5 号簇对
应的 5 号 FAT 表项。
第四步:5 号表项内的表项值为 6,即存储文件的下一个簇为 6 号簇,读取 6 号簇中的内容,查看 6 号簇对
应的 6 号 FAT 表项。
第五步:6 号表项内的表项值为 7,即存储文件的下一个簇为 7 号簇,读取 7 号簇中的内容,查看 7 号簇对
应的 7 号 FAT 表项。
第六步:7 号表项内的表项值为 8,即存储文件的下一个簇为 8 号簇,读取 8 号簇中的内容,查看 8 号簇对
应的 8 号 FAT 表项。
第七步:8 号表项内的表项值为 9,即存储文件的下一个簇为 9 号簇,读取 9 号簇中的内容,查看 9 号簇对
应的 9 号 FAT 表项。
第八步:这时发现 9 号 FAT 表项中的值已是结束标志:0x0FFFFFFF,说明 9 号簇已经是最后一簇了。
也就是说每个表象都是存储下一簇的功能。

__align(4) static unsigned char FileSystemFAT[Fat_Sector_Num*BytesPerSector]={0,};//存储系统FAT16表

接下来研究FAT代码的实现

//根文件名的定义
typedef struct _FileRoot{char filename[11]; //0-10char Attribute;       //11        Attributechar pad[10];          //12-21U16 time;            //22,23 MSB??U16 date;          //24,25 MSB??U16 cluster;           //26,27 first cluster   LSB//文件起始簇号U32 filelength;      //28-31 file length         LSB//文件大小
}FileRoot,*PFileRoot;//根目录结构表
__align(4) static FileRoot FileSystemRoot[FILEROOT_MAX_BUFFER];//根目录缓冲区

1、格式化程序

DBR分区如下:
typedef struct _DiskPart_t{unsigned int TotalCluster;//(19-20)/(13)
unsigned int  BootSector;//启动扇区号为0
unsigned int  RsdSector;// 14-15//保留扇区数RSD_Sector 1
unsigned int  SectorofFatSize;每个分区表占用的扇区数2
unsigned int  TotalCapacity;//(19-20)*(11*12)分区上数据区的字节数
unsigned int  RootEntry;//17-18//根目录项数Directory_Number 0X3B0=944
unsigned int  SecPerClus;//13//每簇扇区数64
unsigned int  TotalSector;//19-20//当前分区的数据扇区总数Total_sector 系统:12224;用户:16320
unsigned int  BytesPerSec;//11-12//每个扇区的大小BytesPerSector,这里为512个字节,
unsigned int Begin_Cluster;//当前分区起始簇
unsigned int Fat_BeginCluster;//FAT起始簇
unsigned int Fat_BeginCluster1;//FAT起始簇
unsigned int Directory_BeginCluster;//根目录起始簇
unsigned int Directory_BeginCluster1;//根目录起始簇
//      数据起始扇区64                    0+1+(2*2)+(944*32+511)/512=64
} DiskPart_t;static int Format_Fat(void)
{   int i=0;int startsecoff=0;//起始扇区偏移预定位置__align(4)  DISK_ENTRY  parttion;//-----------------建立分区表-----------------while(Erase_Cluster(Begin_Clust+i)==FALSE) i++;                   //试擦除当前分区的起始块,直到找到好块为止startsecoff=i;parttion.start_block=Begin_Clust+i;//找到第一个好块作为当前区的起始扇区DiskPart.Begin_Cluster=parttion.start_block;i++;parttion.boot_flag=0X804C594A;parttion.partition_start_sect=0;//记录好上面的当前块信息Fdisk_Fun(FATPART, &parttion);//设立分区表,将其写入NANDFLASH,建立MBRmemset(FileSystemFAT,0,Fat_Sector_Num*BytesPerSector);//初始化FAF文件表memset(FileSystemRoot,0,sizeof(FileSystemRoot));//FAT表应该从第一个簇算起,第一个被启动扇区占领FileSystemFAT[0] = 0xf8;    //FAT12表以"F8 FF FF " 开头,此3字节为介质描述单元,并不参与FAT表簇链关系FileSystemFAT[1] = 0xff;//----------------建立FAT---------------------//找到可用块作为第一个FAT表,每个FAT表一个块while(Erase_Cluster(Begin_Clust+i)==FALSE) //查找一个好块{  i++;if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) ){Uart_Printf("\ndisk is bad!");return FALSE;}}//之所以减去startsecoff是因为前面建立的DBR不属于FAT表管理FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据FileSystemFAT[(i-startsecoff)*2+1]=0xff;DiskPart.Fat_BeginCluster=Begin_Clust+i;//FAT表起始地址//写FAT起始簇writedword(&BPB_Data[40],Begin_Clust+i); //将FAT起始信息写入DBRi++;   //找到可用块作为第二个FAT表,每个FAT表一个块while(Erase_Cluster(Begin_Clust+i)==FALSE){    i++;if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) ){Uart_Printf("\ndisk is bad!");return FALSE;}}FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据FileSystemFAT[(i-startsecoff)*2+1]=0xff;DiskPart.Fat_BeginCluster1=Begin_Clust+i;//FAT1表起始地址//写FAT起始簇writedword(&BPB_Data[44],Begin_Clust+i);i++;   //找到连续的二个块作为根目录,每个FAT表一个块while(Erase_Cluster(Begin_Clust+i)==FALSE){ i++;if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) ){Uart_Printf("\ndisk is bad!");return FALSE;}}FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据FileSystemFAT[(i-startsecoff)*2+1]=0xff;FileSystemFAT[FAT_TABLE_SIZE]=0xa5;DiskPart.Directory_BeginCluster=Begin_Clust+i;//目录的起始地址//写根目录起始簇writedword(&BPB_Data[48],Begin_Clust+i);i++;    while(Erase_Cluster(Begin_Clust+i)==FALSE){  i++;if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) ){Uart_Printf("\ndisk is bad!");return FALSE;}}FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据FileSystemFAT[(i-startsecoff)*2+1]=0xff;DiskPart.Directory_BeginCluster1=Begin_Clust+i; //目录的起始地址Uart_Printf("\nFormat_Fat5");//写根目录起始簇writedword(&BPB_Data[52],Begin_Clust+i);i++;   WriteMBR2Flash();                                 //写启动扇区写到第一块第个分区的启动扇区,完成了MBR写入CreatFAT16();                                     //写FAT表    CreatDirectoryEntry();                            //创建3B0目录项//3B个根目录扇区Init_FAT_Info(FALSE);                             //不进行自动格式化Uart_Printf ("\nFormat Finished!");return TRUE;
}

以上是将FAT的信息将其写入了nandflash

2、程序启动进行的初始化

static int Init_FAT_Info(int AutoFormat)
{int i;INT8U err;DISK_MBR *pMbr;__align(4) unsigned char databuff[BytesPerSector];
///
//读引导扇区if(IsFdisk(databuff)!=TRUE)//判断是否要格式化 //读出MBR的数据goto nofat;pMbr=(DISK_MBR *)databuff; memcpy(&mrb_data,databuff,512);DiskPart.Begin_Cluster=pMbr->partition_entry[FATPART].start_block;//得到起始块if(pMbr->partition_entry[FATPART].boot_flag!=0x804c594a)//看分区表是格式化goto nofat;memcpy(&mrb_data.partition_entry[FATPART],&databuff[0x1bc]+FATPART*sizeof(DISK_ENTRY),sizeof(DISK_ENTRY));ReadPage(pMbr->partition_entry[FATPART].start_block,pMbr->partition_entry[FATPART].partition_start_sect,databuff);//读出DBRif(databuff[0]!=0xeb||databuff[1]!=0x3c||databuff[2]!=0x90||databuff[3]!='L'||databuff[4]!='F'||databuff[5]!='A'||databuff[6]!='T'||databuff[7]!='V'||databuff[8]!='1'||databuff[9]!='.'||databuff[10]!='0'){  //分区表错误Uart_Printf("File Partition Error!\n");goto nofat;}goto fat;
nofat://分区表错需要格式化if (AutoFormat==1)   //自动格式化return Format_Fat();elsereturn FALSE;
fat:DiskPart.BootSector=0;///
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//得到保留扇区数,总扇区数,总扇区数/每簇扇区数得到簇数,是FAT类型的依据ReadPage(DiskPart.Begin_Cluster,DiskPart.BootSector,databuff);//读一个扇区DiskPart.RsdSector=databuff[14]+databuff[15]*256;//保留扇数为1DiskPart.SecPerClus=databuff[13];//每簇扇区数DiskPart.BytesPerSec=databuff[12]*256+databuff[11];//每个扇区大小//使用FAT32的一些功能//DiskPart.TotalSector=databuff[20]*256+databuff[19];//总扇区数DiskPart.TotalSector=(databuff[32]+databuff[33]*256+databuff[34]*256*256+databuff[35]*256*256*256);DiskPart.TotalCapacity=DiskPart.TotalSector*DiskPart.BytesPerSec;//总字节数DiskPart.TotalCluster=DiskPart.TotalSector/DiskPart.SecPerClus;//FAT16的簇总数=扇区总数/每簇扇区数//使用FAT32的一些功能//DiskPart.SectorofFatSize=((databuff[22]+databuff[23]*256));//FAT扇区数DiskPart.SectorofFatSize=(databuff[36]+databuff[37]*256+databuff[38]*256*256+databuff[39]*256*256*256);DiskPart.RootEntry=(databuff[18]*256+databuff[17]);//加FAT和根目录起始簇DiskPart.Fat_BeginCluster=(databuff[40]+databuff[41]*256+databuff[42]*256*256+databuff[43]*256*256*256);DiskPart.Fat_BeginCluster1=(databuff[44]+databuff[45]*256+databuff[46]*256*256+databuff[47]*256*256*256);DiskPart.Directory_BeginCluster=(databuff[48]+databuff[49]*256+databuff[50]*256*256+databuff[51]*256*256*256);DiskPart.Directory_BeginCluster1=(databuff[52]+databuff[53]*256+databuff[54]*256*256+databuff[55]*256*256*256);FAT_TYPE=FAT16;//FAT12;ReadFAT2Mem();//读取FAT分区表到内存的缓冲区中ReadFileRoot2Mem();//读取根目录表到缓冲区中return TRUE;
}

3、打开文件

static CNCFILE* OpenOSFile(char filename[], U32 OpenMode)
{int i=0,j=0,s=0;U32 Pre_Cluster;                                            //当前文件读写的到的簇号__align(4) unsigned char databuff[BytesPerSector];unsigned int CurrentCluster,CurrentSector;unsigned int nFileLength;                                   //文件剩余长度unsigned int k;unsigned int SecNumOfClus;                                 //当前簇已读写扇区数CNCFILE* pfile;INT8U err;char filename1[12]={0};int emptyrootpos=-1;                                           //记录空根目录处FormatFileName(filename1,filename);                   //格式化文件名称,filename1中为11位文件名for(j=0; j<DiskPart.RootEntry;j++){                            //每个扇区有多个目录项if( (FileSystemRoot[j].filename[0]==0 || FileSystemRoot[j].filename[0]==OSFILE_DELETEMARK) && emptyrootpos==-1)//如果找到第一个空根目录emptyrootpos=j;                                   //记录空根目录处
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&文件名存在的情况&&&&&&&&&&&&&&&&&&&&&&&&&&&&&if(!MemcmpNoUpper(filename1, FileSystemRoot[j].filename,11)){    //如果找到某项符合条件寻找文件//  Lcd_Printf("\nFile %s found!",filename1);//Uart_Printf("\nFile %s have been found!NEW",filename1);//JING TESTpfile=(CNCFILE*)OSMemGet(pFileMem,&err);//分配一个内存块,用于存文件缓冲区if(pfile==NULL) return NULL;    //验证是否分配到文件指针pfile->fileCluster=FileSystemRoot[j].cluster;pfile->filesize=nFileLength=FileSystemRoot[j].filelength;pfile->filebufnum=0;pfile->fileCurpos=0;//当前文件读写的偏移pfile->filemode=OpenMode;pfile->rootpos=j;switch(OpenMode){//&&&&&&&&&&&&&&&&&&&&&&&//只读模式,只读一个扇区,指针指向开始,簇指针指向下一个簇case FILEMODE_READ:while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)){CurrentSector=(pfile->fileCluster)*DiskPart.SecPerClus;for(SecNumOfClus=0;(SecNumOfClus<DiskPart.SecPerClus)&&(pfile->filesize>pfile->filebufnum);//(当前簇已读取的扇区数到当前簇最后一个扇区)&&(当前读入的长读已经到达文件长度)SecNumOfClus++)//读一个簇{//读完文件,如果大于一簇,则先读一簇//DiskPart.Begin_Cluster 文件系统的起始块ReadPage(DiskPart.Begin_Cluster+(CurrentSector+SecNumOfClus)/SectorPerClus,(CurrentSector+SecNumOfClus)%SectorPerClus,databuff);//读取当前簇的当前扇区SecNumOfClus的数据到扇区数据缓冲区中databuffif(nFileLength>BytesPerSector) memcpy(pfile->Buffer+pfile->filebufnum, databuff,BytesPerSector);//文件剩余长度nFileLength是否大于一扇区else memcpy(pfile->Buffer+pfile->filebufnum, databuff,nFileLength);nFileLength-=BytesPerSector;pfile->filebufnum+=BytesPerSector;//当前已经读入的字节数}if(pfile->filebufnum>=Block_Size) //当前文件缓冲区是否已经读满{//读到1个簇后即中止缓冲区满pfile->filebufnum=0;//缓冲区指针重新指向开头           break;//缓冲区慢时中止}//根据当前的块号去查找下一个的FAT地址else pfile->fileCluster=NextCluster(pfile->fileCluster);//如果缓冲区没满则继续读下一个簇,??????????}//Uart_Printf("\nFile %s have been read!\n",filename1);pfile->filebufnum=0;//缓冲区指针重新指向开头         break;//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*///只写模式:文件大小为0case FILEMODE_WRITE://无等待取得的邮箱,当取不到写文件邮箱时,直接出错if(!OSMboxAccept(pFileMbox))  {OSMemPut(pFileMem, pfile);pfile=(CNCFILE *)0;return NULL;}pfile->filesize=0;//这里删除原来的簇链,重新分配一个簇给当前文件//将之前的簇全部进行删除DeleteFATList(pfile->fileCluster);pfile->fileCluster=AllocateCluster(0);//查找一个新簇FileSystemRoot[pfile->rootpos].cluster=pfile->fileCluster;FileSystemRoot[pfile->rootpos].filelength=0;memset(pfile->Buffer, sizeof(pfile->Buffer), 0xff);break;
/**修改内容:增加对pfile 指针的安全释放--修改人: caigh--日期:----------------*/default:         if(pfile!=NULL) OSMemPut(pFileMem, pfile);return NULL; //可能是创建模式,不能重名???????}
/**修改内容:在调试时增加对文件结构的保存--修改人: caigh--日期:-----  -*/
#ifdef __debugfile__for(j=0;j<10;j++)    //查找未使用的结构;{   if(TFileStr[j].useflags==0)  {  OSSchedLock();TFileStr[j].useflags=1;OSSchedUnlock();memcpy(TFileStr[j].filename, filename1, 11);TFileStr[j].filemode=pfile->filemode;TFileStr[j].PFile=pfile;//Uart_Printf("\nFile %s have been opennow! The File ID is %d\n->",TFileStr[j].filename,pfile);break;}}if(j<10)
#endifreturn pfile; //找到文件}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}////&&&&&&&&&&&&&&&&&&&&&&&&&文件未找到,是创建文件目录表到缓冲区中&&&&&&&&&&&&&&&&&&&if(OpenMode== (FILEMODE_WRITE|FILEMODE_CREATE) ){   //创建文件//如果没有找到同名文件则创建文件,//创建的时候先建立root目录的数据,在最后,Close的时候//把数据写入root,所以,创建文件以后如果掉电,因为//没有Close,所以,文件对root目录没有影响。----by threewater//  Lcd_Printf("\nCreating CNCFILE %s !\n->",filename1);//Uart_Printf("\nCreating CNCFILE %s !\n->",filename1);//JING TESTpfile=(CNCFILE*)OSMemGet(pFileMem,&err);if(pfile) {//Uart_Printf("\nfile ok");//无等待取得的邮箱,当取不到写文件邮箱时,直接出错//by zbif(!OSMboxAccept(pFileMbox))  {OSMemPut(pFileMem, pfile);pfile=(CNCFILE *)0;return NULL;}//---------------------------------------------------pfile->fileCluster=AllocateCluster(0);//自动寻找下一个空的簇,如入口为零,则返回第一个可用簇// Lcd_Printf("\nThe new cluster is %d\n->",pfile->fileCluster);// Uart_Printf("\nThe new cluster is %d\n->",pfile->fileCluster);//JING TESTpfile->filebufnum=0;pfile->fileCurpos=0;pfile->filemode=OpenMode;}else{Uart_Printf("\nfile NO ok");return NULL;}if(pfile->fileCluster){//接下来在刚才找到的空根目录处创建文件项
/**-------------------------------------------------------------------------------------------------------
**修改内容:增加对没有空簇的判断
**修改人: caigh
** 日 期:
**------------------------------------------------------------------------------------------------------*/              if(emptyrootpos==-1){//目录不够if(pfile!=NULL) OSMemPut(pFileMem, pfile);Uart_Printf("\nDirectory is full!");OSMboxPost(pFileMbox, (void *)1);return NULL;}
/**-----------------------------------------------------------------------------*/
/**-----------------------------------------------------------------------------*///建立根目录到缓冲区//这里好像有点问题,没判断emptyrootpos是否为-1memcpy(FileSystemRoot[emptyrootpos].filename, filename1, 11);FileSystemRoot[emptyrootpos].Attribute=0x20;//AttributeFileSystemRoot[emptyrootpos].time=0x1612;//Create timeFileSystemRoot[emptyrootpos].date=0x2ea2;//Create dateFileSystemRoot[emptyrootpos].cluster=pfile->fileCluster;FileSystemRoot[emptyrootpos].filelength=0;pfile->filesize=0;pfile->rootpos=emptyrootpos;//  Uart_Printf("\nCreat CNCFILE %s Succeed!",filename1);
/**修改内容:在调试时增加对文件结构的保存--修改人: caigh--日期:-----  -*/
#ifdef __debugfile__for(j=0;j<10;j++)    //查找未使用的结构;{   if(TFileStr[j].useflags==0)  {  OSSchedLock();TFileStr[j].useflags=1;OSSchedUnlock();memcpy(TFileStr[j].filename, filename1, 11);TFileStr[j].filemode=pfile->filemode;TFileStr[j].PFile=pfile;break;}}if(j<10)
#endifreturn pfile;}else{//磁盘满?????????if(pfile!=NULL) OSMemPut(pFileMem, pfile);Uart_Printf("Disk is Full!!\n");OSMboxPost(pFileMbox, (void *)1);return NULL;}}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//没找到文件Uart_Printf("\nFile %s is not found!\n->",filename1);return NULL;
}

读文件

static U32 ReadOSFile(CNCFILE* pfile ,U8* ReadBuffer, U32 nReadbyte){U32 i,CurrentSector,SecNumOfClus,Current_Cluster;//,nFileLength;__align(4) unsigned char databuff[BytesPerSector];if(pfile->filemode!=FILEMODE_READ)   //非只读模式则退出return 0;for(i=0;i<nReadbyte;i++){if(pfile->filesize<=pfile->fileCurpos)return i;(*ReadBuffer)=pfile->Buffer[(pfile->fileCurpos++)%Block_Size];//ReadBuffer++;pfile->filebufnum++;//文件当前缓冲区的读写位置if(pfile->filebufnum==Block_Size){//如果到了缓冲区末尾,那就重新读取下一个缓冲区pfile->filebufnum=0;     pfile->fileCluster=Current_Cluster=NextCluster(pfile->fileCluster);  //查找下一个文件的簇while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)){CurrentSector=(pfile->fileCluster)*DiskPart.SecPerClus;for(SecNumOfClus=0;(SecNumOfClus<DiskPart.SecPerClus)&&(pfile->filesize>pfile->filebufnum);//(当前簇已读取的扇区数到当前簇最后一个扇区)&&(当前读入的长读已经到达文件长度)SecNumOfClus++)//读一个簇{//读完文件,如果大于一簇,则先读一簇ReadPage(DiskPart.Begin_Cluster+(CurrentSector+SecNumOfClus)/SectorPerClus,(CurrentSector+SecNumOfClus)%SectorPerClus,databuff);//读取当前簇的当前扇区SecNumOfClus的数据到扇区数据缓冲区中databuffmemcpy(pfile->Buffer+pfile->filebufnum, databuff,BytesPerSector);//文件剩余长度nFileLength是否大于一扇区pfile->filebufnum+=BytesPerSector;//当前已经读入的字节数}if(pfile->filebufnum>=Block_Size) //???当前文件缓冲区是否已经读满{//读到1个簇后即中止缓冲区满pfile->filebufnum=0;//缓冲区指针重新指向开头           break;//缓冲区慢时中止}else pfile->fileCluster=NextCluster(pfile->fileCluster);//如果缓冲区没满则继续读下一个簇,??????????}//Uart_Printf("\nFile %s have been read!\n",filename1);pfile->filebufnum=0;//缓冲区指针重新指向开头}}return i;
}

写操作,也是先写入缓冲区,找过缓冲区之后就写入磁盘中

static U8 WriteOSFile(CNCFILE* pfile, U8* WriteBuffer, U32 nWritebyte)
{int i=0,j=0;U32 Pre_Cluster,Current_Cluster;
//  if((pfile->filemode&0xf) !=FILEMODE_WRITE)
//      return FALSE;if(pfile->fileCluster==0) return FALSE;Current_Cluster=pfile->fileCluster;for(i=0;i<nWritebyte;i++){pfile->Buffer[(pfile->fileCurpos++)%(SectorPerClus*BytesPerSector)]=*WriteBuffer;WriteBuffer++;pfile->filebufnum++;if(pfile->filebufnum>=(SectorPerClus*BytesPerSector)){    //超过一个簇大小//Erase_FileCluster(Current_Cluster);//擦除一个簇,这里不用擦除了,因为在自动分配时已经擦除if(WriteBlock(DiskPart.Begin_Cluster+Current_Cluster,&pfile->Buffer[0])==FALSE)//将当前簇写入FLASH中Uart_Printf("writepage erro!\n");//如果出现这个,则要加自动分配下一簇的代码pfile->filebufnum=0;Pre_Cluster=pfile->fileCluster;pfile->fileCluster=Current_Cluster=NextCluster(pfile->fileCluster);if(((pfile->fileCluster&0xffff)==0xffff)||(pfile->fileCluster==0xffffffff))pfile->fileCluster=Current_Cluster=AllocateCluster(Pre_Cluster);   //查找下一个可用簇,并链接//没有簇可分配了if(pfile->fileCluster==0){//pfile->filesize+=i;  Uart_Printf("disk is full!\n");return FALSE;}}}pfile->filesize+=nWritebyte;  //by threewaterreturn TRUE;
}

定位文件:

1、将输入的偏移量/缓冲量,看看有几个缓冲量
2、找到对应的块缓冲
3、再讲偏移量%缓冲量求余即可
static U32 SeekOSFile(CNCFILE* pfile ,U32 nCurPos)
{U32 i,CurrentSector,SecNumOfClus,Pre_Cluster;
//  if(pfile->filemode!=FILEMODE_READ)
//      return 0;u32 n;__align(4) unsigned char databuff[BytesPerSector];if(nCurPos>=pfile->filesize)//文件大小越界return pfile->fileCurpos;n=nCurPos/Block_Size;//(SectorPerClus*BytesPerSector);这里对齐块的边界,因为一个块有可能是几个簇n=n*(Block_Size/(SectorPerClus*BytesPerSector));//算出簇的定位,对齐块边界pfile->fileCluster=FileSystemRoot[pfile->rootpos].cluster;Pre_Cluster=pfile->fileCluster;while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)&&(n>0)){   //  Uart_Printf("->%d",pfile->fileCluster);Pre_Cluster=pfile->fileCluster;pfile->fileCluster=NextCluster(pfile->fileCluster);n--;}if((pfile->fileCluster==0xffff)||(pfile->fileCluster==0xffffffff)) pfile->fileCluster=Pre_Cluster;CurrentSector=pfile->fileCluster*DiskPart.SecPerClus;pfile->filebufnum=0;while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)){CurrentSector=(pfile->fileCluster)*DiskPart.SecPerClus;for(SecNumOfClus=0;(SecNumOfClus<DiskPart.SecPerClus)&&(pfile->filesize>pfile->filebufnum);//(当前簇已读取的扇区数到当前簇最后一个扇区)&&(当前读入的长读已经到达文件长度)SecNumOfClus++)//读一个簇{//读完文件,如果大于一簇,则先读一簇ReadPage(DiskPart.Begin_Cluster+(CurrentSector+SecNumOfClus)/SectorPerClus,(CurrentSector+SecNumOfClus)%SectorPerClus,databuff);//读取当前簇的当前扇区SecNumOfClus的数据到扇区数据缓冲区中databuffmemcpy(pfile->Buffer+pfile->filebufnum, databuff,BytesPerSector);//文件剩余长度nFileLength是否大于一扇区pfile->filebufnum+=BytesPerSector;//当前已经读入的字节数}if(pfile->filebufnum>=Block_Size) //???当前文件缓冲区是否已经读满{//读到1个簇后即中止缓冲区满pfile->filebufnum=0;//缓冲区指针重新指向开头           break;//缓冲区慢时中止}else pfile->fileCluster=NextCluster(pfile->fileCluster);//如果缓冲区没满则继续读下一个簇,??????????}pfile->filebufnum=(nCurPos%Block_Size);//对齐块的边界//(DiskPart.SecPerClus*512));pfile->fileCurpos=nCurPos;return nCurPos;
}

关闭文件
如果是写方式的话,那就将其写入nandflsh中,并更新FAT表
其他方式的话回收内存就可以了

static int CloseOSFile(CNCFILE* pfile)
{int j,i;U32 Current_Cluster;int syear, smonth,sdate, shour, smin, ssec;if(pfile==NULL) return FALSE;switch(pfile->filemode&0xf){case FILEMODE_WRITE:if(pfile->fileCluster==0){FileSystemRoot[pfile->rootpos].filename[0]=OSFILE_DELETEMARK;//删除目录DeleteFATList(FileSystemRoot[pfile->rootpos].cluster);//删除文件的链表OSMboxPost(pFileMbox, (void *)1);break;}Current_Cluster=pfile->fileCluster;if(Current_Cluster!=0)//Erase_FileCluster(Current_Cluster);//不用擦除当前簇,因为已经分配时擦除过{   if(WriteBlock(DiskPart.Begin_Cluster+Current_Cluster,&pfile->Buffer[0])==FALSE)Uart_Printf("writepage erro!\n");//写入root表FileSystemRoot[pfile->rootpos].filelength=pfile->filesize;GetRtcTime(&syear, &smonth, &sdate, &shour, &smin, &ssec);FileSystemRoot[pfile->rootpos].time=RtcTimeToFileTime(shour,smin,ssec);//Create timeFileSystemRoot[pfile->rootpos].date=RtcDateToFileDate(syear-1980,smonth,sdate);//Create dateWriteFATFromMem();// 将FAT写入FLASH中WriteFileRootFromMem();//将根目录写入FALSH中}else{DeleteFATList(FileSystemRoot[pfile->rootpos].cluster);FileSystemRoot[pfile->rootpos].filename[0]=OSFILE_DELETEMARK;}//释放写文件邮箱//OSMboxPost(pFileMbox, (void *)1);//-------------------------------------------break;default:break;}/**修改内容:在调试时增加对文件结构的保存--修改人: caigh--日期:-----  -*/
#ifdef __debugfile__for(j=0;j<10;j++)    //查找未使用的结构;{   if(TFileStr[j].useflags==1)if(TFileStr[j].PFile==pfile)  {  OSSchedLock();TFileStr[j].useflags=0;OSSchedUnlock();//Uart_Printf("\nFile %s have been CLOSEED!now The File ID is %d\n->",TFileStr[j].filename,pfile);break;}}
#endifOSMemPut(pFileMem, pfile);//<--------add by threewaterreturn TRUE;
}

建立FAT文件系统学习笔记相关推荐

  1. mysql原生建立索引_MySQL学习笔记之索引

    索引是存储引擎用于快速找到记录的一种数据结构. 索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要.在数据量较小且负载较低时,不恰当的索引对性能的影响可能还不明显,但 ...

  2. 大数据-Hadoop文件系统- 学习笔记 -BH2

    Hadoop文件系统(HDFS) HDFS的概念和特性 首先,它是一个文件系统,用于存储文件,通过统一的命名空间--目录树来定位文件 其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器 ...

  3. FATFS文件系统学习笔记

    什么是文件系统       负责管理和存储文件信息的软件机构,在磁盘上组织文件的方法. 常用的文件系统       FAT/FATFS  小型嵌入式系统       NTFS   WINDOWS    ...

  4. 韦东山uboot_内核_根文件系统学习笔记4.4-第004课_根文件系统-第004节_构建根文件系统之构建根文件系统

    一 最小的根文件系统需要的项(笔记4.1 4.2小结) (init 进程需要) 打开终端: /dev/console, /dev/NULL 不设置 inittab 格式中的 id(标准输入.输出和标准 ...

  5. [文件系统]文件系统学习笔记(一)---基本概念以及inode

    1,文件系统基本概念 文件系统是一种用来存储和组织计算机文件.目录及其包含的数据的方法,它使文件.目录以及数据的查找和访问得到简化. 2,硬链接和软链接的区别 硬链接和软链接的区别 –         ...

  6. [文件系统]文件系统学习笔记(十)---杂项

    1,在一个系统上,比如smartphone平台,有很多分区,比如/data和/system分区都是ext4文件系统,但是系统中还是只有一个file_system_type的成员,不过每个分区对应的ex ...

  7. Linux的ext4文件系统学习笔记

    补充:设备独立性 Linux中,设备驱动以文件形式表示,用户操作逻辑设备就是操作文件,而不是具体的物理设备,也就是说,用户操作的是功能,是黑箱,而不是真正的实体. APP操作的都是逻辑设备,而逻辑设备 ...

  8. 获取两个数据的交集_Redis学习笔记统计该如何选择数据类型

    关注爱因诗贤每天进步一点点导读 在业务场景中经常需要统计,如某直播累计观看人数.独立访客人数.历史总观看人数等等,再比如要统计某学生某月的签到情况等,遇到统计的情况,就需要思考如何合理地选择 Redi ...

  9. STM32CubeMX学习笔记(25)——FatFs文件系统使用(操作SPI Flash)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

最新文章

  1. html中运行php脚本,php脚本在html文件中
  2. ubuntu 12.04安装 jdk
  3. 文件传送到服务器的软件,远程服务器文件传输软件
  4. pytorch保存和加载模型state_dict
  5. 暑期英语学习(词组积累)【持续更新中】
  6. 图片支持滚轮缩放(缩放中心为鼠标位置)_JS实现图片缩放、拖动、剪裁、预览及保存效果...
  7. 中兴天机Axon 10 Pro系列中国发布:售价3199元起
  8. 应用虑镜特效时遇到浏览器权限问题
  9. 从程序设计、tqdm到lambda:python的“奇技淫巧”,让实现效率翻倍【科学计算类】
  10. 【渝粤题库】陕西师范大学800000 地图学原理
  11. 几种调用WebService的方法
  12. Tests of the Equality of Two Means
  13. ipad横竖屏切换,页面适配方法
  14. python代码服务器上运行报错
  15. 对于pdf转图片linux乱码的解决
  16. HDU-5857-Median
  17. AES加密和解密详解
  18. 5.Django路由path和re_path详解
  19. 【简单快捷教会你】如何正确使用animate.css,各种动态效果。
  20. python操作jira修改status及写入comment

热门文章

  1. Python selenium 模拟登录QQ空间
  2. Kindle 可旋转桌面时钟
  3. Rasa课程、Rasa培训、Rasa面试、Rasa实战系列之 Countvectors and Spelling Errors
  4. DELPHI窗体属性介绍
  5. 中国石油大学《化工原理二》
  6. 网络安全课程笔记(1)
  7. ubuntu下添加日语输入法
  8. 运行ant-design-pro报错ERROR in ./node_modules/swagger-ui-react/swagger-ui.js 2:107055-107070Module not
  9. nginx自定义404错误页面
  10. 计算机专业专科可以进的国企,专科学这四个专业!考国企、事业编制会容易很多...