FAT32文件

/*----------------------------------------------
 * 模 块 名:文件系统
 * 功能描述:读写基于FAT32格式的数据
 * 调试平台:UMP3
 *
 * 当前版本:1.0
 * 作    者:xx
 * 完成日期:2010-6-28
 * 存在BUG:未知
 * 调试结果:完成调试
 *
 * 说    明:本文件系统参考了znFAT的编程思想,在znFAT的基础上进行了相应的简化           
  ----------------------------------------------*/
#include "fat32.h" 
#include "ch375kk.h"  //存储设备的扇区读写驱动,这里是U盘
#include "string.h"
#include "uart.h"  //串口监控




/*---------------------------------------------------------*
 * 文件系统
/*---------------------------------------------------------*
 * 函数名/局部变量/全局变量命名规则:
 * 1、凡是函数名,由几个单词或者几个单词的简写组成,每个单词的第一个字母大写
 * 2、全局变量第一个单词首字母小写,后面的单词首字母大写
 * 3、局部变量所有单词的首字母都小写(约定俗称的单词除外,如USB、SD等除外)
 * 4、变量和函数名不出现下划线
 * 5、宏定义都用大写,几个单词直接之间用下划线连接起来
 * 6、结构体尽量按照变量的命名法则
 * 7、指针变量在变量名前加p,如pArg表示为一个指针变量
 *---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 全局变量
 *---------------------------------------------------------*/
struct directory idata tempRec;
INT8 tempDirName[13];   //全局目录名,当进入一个目录后,用来记录目录名
UINT32 tempDirCluster; //记录当前目录的首簇号,当进入一个目录后用此全局变量记录当前目录的首簇号
UINT32  tempLastCluster; //记录当前簇的上一个访问簇的,当访问当前簇失败后,还可以返回上一个有效簇
UINT8 FAT32Buffer[512]; //数据缓冲区,常用的falsh每一簇为512个字节,所有我们定义缓冲区为512个字节
extern struct FAT32InitArg *pArg; //初始化参数结构体指针,用以指向某一存储设备的初始化参数结构体,由外部提供
extern UINT8 DevNo;         //用来表示设备类型:如U盘为1,SD卡位0,增加程序的兼容性


unsigned char (*pRS)(unsigned long,unsigned char *); //指向实际存储设备的读扇区函数的函数指针,用以实现对设备的支持
unsigned char (*pWS)(unsigned long,unsigned char *); //指向实际存储设备的写扇区函数的函数指针,用以实现对设备的支持








/*---------------------------------------------------------*
 * 函 数 名:FAT32ReadSector
 * 隶属模块:FAT32文件系统
 * 全局变量:无
 * 函数功能:调用ch375的读函数,在指定的扇区地址上读一扇区的数据
 * 输入变量:addr,扇区地址;buf,存放数据的缓冲区
 * 调用函数:CH375ReadSector
 * 返 回 值:读取数据的状态,返回状态与FAT32ReadSector()一样
 * 说    明:
 *---------------------------------------------------------*/
UINT8 FAT32ReadSector(UINT32 addr,UINT8 *buf) 
{
  switch(DevNo)
  {
  case SDCARD:
          //pRS=SD_Read_Sector;
          break;
  case UDISK:
          pRS=CH375ReadSector;
          break;
  case CFCARD:
          //pRS=CFRead_Sector;
          break;
  case OTHER:
          break;
  }
  return (*pRS)(addr,buf);   //指针函数,替换成实际存储器的扇区读函数,这里是SD卡扇区读函数
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32WriteSector
 * 隶属模块:FAT32文件系统
 * 全局变量:无
 * 函数功能:调用ch375的写函数,在指定的扇区地址上写一扇区的数据
 * 输入变量:addr,扇区地址;buf,存放数据的缓冲区
 * 调用函数:CH375ReadSector
 * 返 回 值:写数据的状态,返回状态与FAT32WriteSector()一样
 * 说    明:
 *---------------------------------------------------------*/
UINT8 FAT32WriteSector(UINT32 addr,UINT8 *buf)
{
  switch(DevNo)
  {
  case SDCARD:
          //pWS=SD_Write_Sector;
          break;
  case UDISK:
          pWS=CH375WriteSector;
          break;
  case CFCARD:
          //pWS=CF_Write_Sector;
          //无
          break;
  case OTHER:
          //无
          break;
  }
  return (*pWS)(addr,buf); //指针函数,替换成实际存储器的扇区写函数,这里是SD卡扇区写函数
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:LE2BE
 * 隶属模块:FAT32文件系统
 * 全局变量:无
 * 函数功能:将FAT32的小端模式改成51单片机通用的大端模式
 * 输入变量:dat,小端模式的数据;len,数据长度
 * 调用函数:无
 * 返 回 值:temp,转换后的数据(大端模式)
 * 说    明:比如:小端模块的  0x33 0x22 0x11 0x00  (低字节在前)
             转为大端模式后为 0x00 0x11 0x22 0x33  (高字节在前)
             所表达的数值为   0x00112233
             (CISC的CPU通常是小端的,所以FAT32也设计为小端,而单片机
              这种RISC的CPU,通常来说都是大端的,所以需要这个函数将字
              节的存放次序进行调整,才能得到正确的数值)
 8051单片机先读取数据的高字节,然后再读取数据的低字节
 *---------------------------------------------------------*/
UINT32 LE2BE(UINT8 *dat, UINT8 len) 
{
  UINT32 temp = 0;
  UINT32 fact = 1;
  UINT8  i = 0;
  for(i = 0; i < len; i++)
  {
  temp += dat[i]*fact; //读取第一个8位的数据,+第二个八位的数据<<8  +第三个八位读数据<<16  .....
  fact  =fact<<8;
  }
  return temp;
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:lowcase2Uppercase
 * 隶属模块:FAT32文件系统
 * 全局变量:无
 * 函数功能:把小写字母变换成大写字母
 * 输入变量:c,需要转换的字母
 * 调用函数:无
 * 返 回 值:c,转换后的字母
 * 说    明:根据ascii码来修改,'c'表示ascii码,c表示一个变量
 *---------------------------------------------------------*/
INT8 L2U(INT8 c)
{
if(c > 'a' && c < 'z') //c为小写字母,进行一系列的转换
{
return(c + 'A' - 'a');
}
else //c为大写字母,不需要更改,在fat32存储时统一用大写字母
{
return c;
}


}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32IsMBR
 * 隶属模块:FAT32文件系统
 * 全局变量:FAT32Buffer
 * 函数功能:判断当前falsh是否存在MBR(主引导扇区)
 * 输入变量:无
 * 调用函数:FAT32ReadSector
 * 返 回 值:存在MBR,返回值为1,不存在返回0,
 * 说    明:一般的U盘不需要操作系统引导,常常不存在MBR
 *---------------------------------------------------------*/
UINT8 FAT32IsMBR()
{
UINT8 result;
FAT32ReadSector(0, FAT32Buffer); //读falsh的0扇区是数据,如果存在MBR,一般就在0扇区
if(FAT32Buffer[0] != 0xeb) //DBR的第一个字节是0xEB,如果0扇区为DBR,则不存在MBR
{
result = 1; //存在MBR,需要对MBR进行解析
}
else
{
result = 0; //falsh以DBR开头,0扇区为DBR
}
return result;


}
/*---------------------------------------------------------*/
/*---------------------------------------------------------*
 * 函 数 名:FAT32FindDBR
 * 隶属模块:FAT32文件系统
 * 全局变量:FAT32Buffer
 * 函数功能:得到DBR所在的扇区号(如果没有MBR,则DBR就在0扇区)
 * 输入变量:无
 * 调用函数:FAT32ReadSector(),LE2BE()
 * 返 回 值:secDBR,DBR的扇区地址,读写fat32,首先需要接卸DBR(操作系统引导码)
 * 说    明:DBR中包含了很多有用的参数信息,因此正确定位DBR扇区的位置,是极为
        重要的,后面将有专门的函数对DBR进行解析,正确解析DBR是实现FAT32的基础
 *---------------------------------------------------------*/
UINT16 FAT32FindDBR()
{
UINT16 secDBR;
FAT32ReadSector(0, FAT32Buffer);//读falsh的0扇区是数据,如果存在MBR,一般就在0扇区
if(FAT32Buffer[0] != 0xeb)   //0xeb是DBR的第一个字节,0扇区不是DBR,表示存在MBR
{
//如果存在MBR的话,DBR的扇区地址在MBR的4个分区记录中查找
//具体操作参考FAT32的官方资料
secDBR = LE2BE((((struct PartSector *)(FAT32Buffer)) ->Part[0]).StartLBA, 4);
}
else
{
secDBR = 0; //不存在DBR,则falsh的0扇区就是DBR,即DBR的初始扇区地址为0
}
return secDBR;
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32GetTotalSize
 * 隶属模块:FAT32文件系统
 * 全局变量:pArg指针指向Init_Arg_UDISK全局结构体,FAT32Buffer
 * 函数功能:获取分区容量值,单位为字节
 * 输入变量:无
 * 调用函数:FAT32ReadSector(),LE2BE()
 * 返 回 值:返回磁盘的总容量
 * 说    明:1、对FAT32Buffer空间进行初始化
  2、为FAT32Init的FAT32Buffer填充值,将DBR的相关数据填充到
 *---------------------------------------------------------*/
UINT32 FAT32GetTotalSize()
{
UINT32 temp;
//将BPB所在扇区的数据读取出来,放入缓存区
FAT32ReadSector(pArg -> BPBSectorNo, FAT32Buffer);
//falsh容量大小等于文件扇区数*每扇区字节数
temp = LE2BE(((struct FAT32BPB *)(FAT32Buffer)) -> BPBTotSec32, 4) * pArg -> BytesPerSector;
return temp;
}
/*---------------------------------------------------------*/
/*---------------------------------------------------------*
 * 函 数 名:SearchLastUsableCluster
 * 隶属模块:FAT32文件系统
 * 全局变量:FAT32Buffer
 * 函数功能:找出最近的一个可用空闲簇
 * 输入变量:无
 * 调用函数:FAT32ReadSector(),LE2BE()
 * 返 回 值:下一个可用空闲簇的簇号
 * 说    明:FAT32中的FSInfo扇区(绝对1扇区)中记录了最近的一个可用空闲簇
 *---------------------------------------------------------*/
UINT32 SearchLastUsableCluster()
{
//读取BPB中FSInfo的信息放到数据缓冲区中
FAT32ReadSector(1 + pArg -> BPBSectorNo, FAT32Buffer);
return LE2BE(((struct FSInfo *)(FAT32Buffer)) -> LastCluster, 4);


}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32Init
 * 隶属模块:FAT32文件系统
 * 全局变量:FAT32Buffer,pArg指针指向Init_Arg_UDISK全局结构体,
 * 函数功能:磁盘初始化
 * 输入变量:无
 * 调用函数:......
 * 返 回 值:无
 * 说    明:BPB的关键信息装在结构体Init_Arg_UDISK,以供调用
 *---------------------------------------------------------*/
void FAT32Init()
{
struct FAT32BPB *bpb;
bpb = (struct FAT32BPB *)(FAT32Buffer);


pArg -> DEVNo           = DevNo; //设备类型
pArg -> BPBSectorNo   = FAT32FindDBR(); //FAT32FindDBR()可以返回DBR所在的扇区号
pArg -> TotalSize = FAT32GetTotalSize(); //FAT32GetTotalSize()可以返回磁盘的总容量,单位是兆,
//在其操作中它将DBR第一字节开始的数据存到FAT32Buffer
pArg -> FirstDirCluster = LE2BE(bpb -> BPBRootClus, 4); //装入根目录簇号到FirstDirClust中


pArg -> BytesPerSector = LE2BE(bpb -> BPBBytesPerSec,2); //装入每扇区字节数到BytesPerSector中
pArg -> FATsectors = LE2BE(bpb -> BPBFATSz32,4); //装入FAT表占用的扇区数到FATsectors中
pArg -> SectorsPerCluster = LE2BE(bpb -> BPBSecPerClus,1);//装入每簇扇区数到SectorsPerCluster 中
pArg -> FirstFATSector = LE2BE(bpb -> BPBRsvdSecCnt, 2) + pArg->BPBSectorNo; //装入第一个FAT表扇区号到FirstFATSector 中
pArg -> FirstDirSector  = (pArg -> FirstFATSector) + (bpb -> BPBNumFATs[0]) * (pArg -> FATsectors);//装入第一个目录扇区到FirstDirSector中


tempLastCluster = SearchLastUsableCluster(); //下一个空闲的簇
}
/*---------------------------------------------------------*/




/*---------------------------------------------------------*
 * 函 数 名:FAT32GetRemainCap
 * 隶属模块:FAT32文件系统
 * 全局变量:FAT32Buffer,pArg指针指向Init_Arg_UDISK全局结构体
 * 函数功能:返回磁盘的剩余空间数
 * 输入变量:无
 * 调用函数:FAT32ReadSector(),LE2BE()
 * 返 回 值:磁盘的剩余空间数
 * 说    明:本函数检查结构FSInfo的数据,然后判断是存在多大的剩余空间
 *---------------------------------------------------------*/
UINT32 FAT32GetRemainCap()
{
  FAT32ReadSector(1 + pArg -> BPBSectorNo, FAT32Buffer);
//如果文件系统的下一空闲族项为0xff,表示fat的簇项都为0xffff,则盘中没有存储数据
  if(((struct FSInfo *)FAT32Buffer) -> FreeCluster[0] == 0xff 
  && ((struct FSInfo *)FAT32Buffer) -> FreeCluster[1] == 0xff 
  && ((struct FSInfo *)FAT32Buffer) -> FreeCluster[2] == 0xff 
  && ((struct FSInfo *)FAT32Buffer) -> FreeCluster[3] == 0xff)
  {
  return pArg -> TotalSize; //磁盘空闲空间为磁盘的容量
}
  else
{
  //c磁盘的空闲空间为;文件系统信息结构体中的空闲簇数*每簇扇区数*每扇区字节数
return LE2BE(((struct FSInfo *)FAT32Buffer) -> FreeCluster, 4) * (pArg -> SectorsPerCluster * pArg -> BytesPerSector); 
}
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32GetNextCluster
 * 隶属模块:FAT32文件系统
 * 全局变量:FAT32Buffer,
 * 函数功能:获取下一簇可用的空闲簇
 * 输入变量:LastCluster:基准簇号
 * 调用函数:FAT32ReadSector
 * 返 回 值:下一个簇的簇号
 * 说    明:获得下一簇的簇号,就是凭借FAT表中所记录的簇链关系来实现的
 *---------------------------------------------------------*/
UINT32 FAT32GetNextCluster(UINT32 lastcluster)
{
UINT32 tempcluster;
struct FAT32FAT *pFAT;   //结构体定义请看FAT32.h
struct FAT32FATItem *pFATItem; //结构体定义请看FAT32.h

//temp表示LastCluster在Fat表中对应的扇区号:FAT开始扇区 + (簇号*4)/512;每隔簇号占4个字节
tempcluster = (lastcluster/128) + (pArg -> FirstFATSector);
FAT32ReadSector(tempcluster, FAT32Buffer); //获取上一簇所在的FAT的512个字节
pFAT = (struct FAT32FAT *)FAT32Buffer; //pFAT指针指向缓冲区
pFATItem = &(pFAT -> Items)[lastcluster%128]; //求得上一个簇在FAT表中的簇号
return(LE2BE((UINT8 *)pFATItem,4));
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:CompareDirName
 * 隶属模块:FAT32文件系统
 * 全局变量:无
 * 函数功能:比较两个目录名,
 * 输入变量:namea,nameb,互相比较的两个字符串
 * 调用函数:无
 * 返 回 值:如果两个目录名相同就返回1,否则为0
 * 说    明:已知文件名为8个字节,扩展名为3个字节
 *---------------------------------------------------------*/
UINT8 CompareDirName(UINT8 *namea, UINT8 *nameb)
{
UINT8 i;
for(i = 0; i < 8; i++)
{
if(namea[i] != nameb[i]) //目录名不相同则返回0
{
return 0;
}
}
return 1; //目录名不相同则返回0,相同返回1
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:文件名匹配(支持带*?通配符的文件名的匹配)
 * 隶属模块:FAT32文件系统
 * 全局变量:无
 * 函数功能:比较目录名与文件名是否匹配
 * 输入变量:pathname,从目录路径中提取出来的文件名,filename,文件名
 * 调用函数:strchr,
 * 返 回 值:如果两个文件名匹配就返回1,否则为0
 * 说    明:
 *---------------------------------------------------------*/
UINT8 MatchFileName(INT8 *pathname, INT8 *filename)
{
INT16 match,ndone;
INT8 *ppathname, *pfilename; //定义指针
ppathname = pathname;
pfilename = filename;
match = 1; //初始化,文件名匹配
ndone = 1; //初始化,文件名比较没有完成
while(ndone)
{
switch(*ppathname)
{
case '*':
ppathname++;  //目录指针++
pfilename = strchr(pfilename, *ppathname);//搜索'*' 的下一个字符在pfilename中的位置
if(pfilename == NULL)  //如果搜索后返回的地址为空,则重新将filename的地址赋给pfilename指针
{
pfilename = filename; //重新比较
while(*pfilename)
{
pfilename++;
}
}
break;
case '?': //跳过一个比较的字符
ppathname++;
pfilename++;
break;
case 0:
if(*pfilename != 0) //匹配失败,匹配过程结束
{
match = 0;
}
ndone = 0;
break;
default:
if(*ppathname == *pfilename)
{
ppathname++;
pfilename++;


}
else
{
match = 0;
ndone = 0;
}
break;
}
}
return match;
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:Str2Up
 * 隶属模块:FAT32文件系统
 * 函数功能:将字符串中的小写字符都转为大写字符
 * 输入变量:str:指向待转换的字符串
 * 全局变量:无
 * 调用函数:L2U()
 * 返 回 值:无
 * 说    明:短文件名的情况下,文件名中的字符其实都是大写字符,为了方便,将文件名都转为大写
 *---------------------------------------------------------*/
void Str2Up(char *str)
{
  unsigned char len=strlen(str),i;
  for(i=0;i<len;i++)
  {
  str[i]=L2U(str[i]); 

}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32ToFileName
 * 隶属模块:FAT32文件系统
 * 函数功能:FAT32的文件目录项的文件名字段(8个字节),转为普通的文件名
             如:ABC     MP3 将转为 ABC.MP3
 * 输入变量:dName:指向文件目录项的文件名字段的指针
  pName:指向转换完成后的文件名
 * 全局变量:无
 * 调用函数:L2U()
 * 返 回 值:无
 * 说    明:此函数配合上面的FilenameMatch函数,就可以实现对文件名通配匹配
 *---------------------------------------------------------*/
void FAT32ToFileName(char *dName,char *pName)
{
  char i  =7, j = 0, k = 0;
  while(dName[i--] == ' '); //如果文件名不足8个字节,用‘ ’填充,首先找出文件名总共有几个字节,假设8个字节都有效,运算完后,i=6
  for(j = 0; j < i + 2; j++) //这就是为什么 j=i+2=8;
{
pName[j] = L2U(dName[j]);//将文件名复制到pName中,如果文件名占8个字节,则复制九个字节
}
  pName[j++] = '.'; //在第j个字节处加一个‘.’运算后j=9
  i = 10;
  while(dName[i--]==' '); //寻找扩展名,扩展名3个字节,与文件名相加为11个字节,如果扩展名为3个字节,运算i=9
  k = j + i - 6; //运算完后k=9+9-6=12; 
  i = 0;
  for(; j < k;j++) //正好加上'.'后,文件名为12个字节;从文件名+'.'后继续复制
{
pName[j] = dName[8+(i++)];
}
  pName[j] = 0; 
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32EnterDir
 * 隶属模块:FAT32文件系统
 * 函数功能:进入文件目录,将文件目录的首簇地址保存在全局变量中
 * 输入变量:path:目录的路径 形如:"\\dir1\\dir2\\" ,最后一定是以\\结束
 * 全局变量:tempDirCluster,tempDirName
 * 调用函数:FAT32ReadSector()
 * 返 回 值:curcluster,进入的当前目录的首簇号
 * 说    明:进入目录
 *---------------------------------------------------------*/
UINT32 FAT32EnterDir( UINT8 *path)
{
UINT32 curcluster; //当前扇区号
UINT32 sectemp; //在本程序中表示剩余扇区数
UINT32 isec,idir;
UINT32 oldcluster; //上一簇的簇号
UINT8 i=1, count=0; 
UINT8 flag =0; //进入指定目录的标志
struct directory *pdir;
UINT8 name[20];   //目录名存储区


curcluster = pArg -> FirstDirCluster; //初始化,当前簇为根目录的开始簇
if(path[1]== 0 && path[0]=='\\') //如果只有根目录,就返回根目录的簇号
{
return curcluster;
}
else   //如果指定路径有两层以上路径
{
//为什么用i赋初值1,是因为path第0个字节始终为'\\',从第1个字节开始,首先将目录名复制到name中
//8个字节的剩余字节填充空格'',遇到'\\',则分析name中的目录并求出目录所在簇的初始扇区,然后依次直到path[i]=0
while(path[i] != 0) //搜索路径的每一个字符
{
if(path[i] == '\\')   //如果字符为'\\',表示目录添加一层 *
{
for(; count < 8; count++) //每个文件名为8个字节,前几个字节从path中把路径复制过来,其他用''填充
{
name[count]= ' '; //不足8个字节的目录名,剩余字节用空格补全,同时以0表示结束
}
name[count] = 0; //文件名为13个字节,其中扩展名占3个字节,目录的扩展名为0,0表示结束
count = 0; //count清零,name[]数组供下一级目录存储目录名使用
do
{
sectemp = SOC(curcluster); //*sec_temp = 目录所在簇的初始扇区
for(isec = sectemp; isec < sectemp + pArg -> SectorsPerCluster; isec++)
{
FAT32ReadSector(isec, FAT32Buffer);
//在当前扇区中以目录为单位查找所需文件
for(idir = 0; idir < pArg -> BytesPerSector; idir += sizeof(struct directory))
{
//以目录项为单位查找文件,目录也是以文件的方式存储
pdir = (struct directory *)(FAT32Buffer + idir);
//将目录项的文件名改成普通的文件名放在temp_file_name中
if(CompareDirName(pdir -> deName, name));
{
flag =1;   //目录名匹配,进入指定目录的标志
curcluster = LE2BE(pdir -> deLowCluster, 2) + LE2BE(pdir -> deHighCluster, 2) * 62256;
idir   = pArg -> BytesPerSector;
isec       = sectemp + pArg -> SectorsPerCluster;
}
}
}
oldcluster = curcluster;//保存上一个路径扇区
}
//如果标志位flag=0(未找到对应的目录),同时更新当前寻找簇信息,并且下一个扇区不为?????,则继续循环
//如果进入指定目录,则不再循环
while(!flag && (curcluster = FAT32GetNextCluster(curcluster)) != 0x0fffffff);

//当前目录没有找到,则返回上一层目录
if(!flag)
{
tempDirCluster = oldcluster; //上一层目录的簇号保存到全局变量tempDirCluster中
strcpy(tempDirName, name); //保存name????bug
flag = 0;
return 0;
}
flag=0; //标志位清零,为下一级目录做准备
}
else   // 如果字符不为'\\',表示字符为目录名的一部分 *
{
name[count++] = L2U(path[i]); //将路径名转化为文件名,包括字符'\\'
}
i++;   //寻找下一个字符,
}
}
name[count] = 0; //路径名寻找完毕,最后一个字节用0填充
// flag = 1; //???
tempDirCluster = curcluster; //将当前目录的簇号保存到全局变量tempDirCluster中
strcpy(tempDirName,name); //将当前目录的路径保存到全局变量tempDirName中
return (curcluster);
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32OpenFile
 * 隶属模块:FAT32文件系统
 * 函数功能:打开一个文件,并将文件信息存储到一个指针pfileinfo指向的空间中
 * 输入变量:pfileinfo,文件信息存储空间,filepath,文件路径,itemnum,与之匹配的文件的第几个
 * 全局变量:tempDirName,tempDirName
 * 调用函数:
 * 返 回 值:0:成功 1:文件不存在 2:目录不存在
 * 说    明:打开文件不成功有很多原因,比如文件不存在、文件的某一级目录不存在
        通配情况下满足条件的文件项数小于item的值等等
  通常情况下,文件名中没有通配符,item的值我们取0就可以了
 *---------------------------------------------------------*/
UINT8 FAT32OpenFile(struct FileInfoStruct *pfileinfo, INT8 *filepath, unsigned long itemnum)
{
UINT32 filecurcluster, sectemp, isec,ifile, iitemnum = 0;
UINT8 flag = 0, i= 0; 
UINT8 indexdepth = 0;//目录级深度初始化为0
UINT8 tempfilename[13];
struct directory *pfile;
while(filepath[i] != 0) //如果文件路径不为空,表示进入下一级目录,
{
if(filepath[i] == '\\')
{
indexdepth = i; //目录级加1,进入下一层目录
}
i++;
}
if(filecurcluster = FAT32EnterDir(filepath)) //进入路径所在目录成功
{
Str2Up(tempDirName); //变换全局变量,将目录名小写字母变换成大写字母
do
{
sectemp =SOC(filecurcluster); //获得当前簇的初始扇区号
//从目录项的当前簇的初始扇区开始,读一个簇的字节
for(isec = sectemp; isec < sectemp + pArg -> SectorsPerCluster; isec++)
{
FAT32ReadSector(isec, FAT32Buffer);
//在当前扇区中以目录为单位查找所需文件
for(ifile = 0; ifile < pArg -> BytesPerSector; ifile += sizeof(struct directory))
{
pfile = (struct directory *)(FAT32Buffer + ifile);
//将目录项的文件名改成普通的文件名放在temp_file_name中
FAT32ToFileName(pfile -> deName, tempfilename);
if((MatchFileName(tempDirName, tempfilename)) && (pfile -> deName[0] != 0xe5) && (pfile -> deAttributes & 0x20))
{
if(itemnum == iitemnum)       //文件枚举的所以文件中指定的那个文件找到
{
flag = 1;
//文件的当前簇号
filecurcluster = LE2BE(pfile -> deLowCluster, 2) + LE2BE(pfile -> deHighCluster, 2)*65536;


pfileinfo -> FileSize = LE2BE(pfile->deFileSize, 4); //文件的大小
strcpy(pfileinfo->FileName, tempfilename); //文件名记录到相应的目录结构中去
pfileinfo -> FileStartCluster = LE2BE(pfile -> deLowCluster, 2) + LE2BE(pfile -> deHighCluster, 2) * 65536;//文件的初始簇
pfileinfo -> FileCurCluster   = pfileinfo -> FileStartCluster;
pfileinfo -> FileCurSector    = SOC(pfileinfo->FileStartCluster); //文件的当前扇区 = 文件当前簇的初始扇区
pfileinfo -> FileCurPos       = 0; //文件的当前地址 = 0
pfileinfo -> FileCurOffset    = 0; //文件的当前偏移量 = 0
pfileinfo -> Rec_Sec          = isec; //文件的目录项所在扇区
pfileinfo -> nRec             = ifile; //文件的目录项所在扇区中的位置


pfileinfo -> FileAttr = pfile -> deAttributes; //文件的属性
sectemp     = LE2BE(pfile -> deCTime, 2); //sectemp指向文件创建的时间
(pfileinfo -> FileCreateTime).sec = (sectemp & 0x001f) * 2; //文件创建的时间
(pfileinfo -> FileCreateTime).min = ((sectemp >> 5) & 0x003f);
(pfileinfo -> FileCreateTime).hour = ((sectemp >> 11) & 0x001f);
sectemp = LE2BE(pfile -> deCDate,2); //文件创建的日期
(pfileinfo -> FileCreateDate).day = ((sectemp) & 0x001f);
(pfileinfo -> FileCreateDate).month = ((sectemp >> 5) & 0x000f);
(pfileinfo -> FileCreateDate).year = ((sectemp >> 9) & 0x007f) + 1980;


sectemp = LE2BE(pfile -> deMTime,2);
(pfileinfo -> FileMTime).sec = (sectemp &0x001f)*2; //文件修改的时间
(pfileinfo -> FileMTime).min = ((sectemp>>5)&0x003f);
(pfileinfo -> FileMTime).hour = ((sectemp>>11)&0x001f);
sectemp = LE2BE(pfile->deMDate,2); //文件创建的日期
(pfileinfo -> FileMDate).day = ((sectemp)&0x001f);
(pfileinfo -> FileMDate).month = ((sectemp>>5)&0x000f);
(pfileinfo -> FileMDate).year = ((sectemp>>9)&0x007f)+1980;


sectemp = LE2BE(pfile->deADate,2); //文件访问的日期
(pfileinfo -> FileADate).day = ((sectemp)&0x001f);
(pfileinfo -> FileADate).month = ((sectemp>>5)&0x000f);
(pfileinfo -> FileADate).year = ((sectemp>>9)&0x007f)+1980;
   
ifile = pArg -> BytesPerSector; //枚举文件的个数达到了,?????用处
isec  = sectemp + pArg -> SectorsPerCluster;
}
else
{
  iitemnum++;

}
}
}
}
while(!flag && (filecurcluster = FAT32GetNextCluster(filecurcluster)) != 0x0fffffff);
if(!flag) //目录存在,没有在当前目录找到文件
{
return 1;
}
return 0;
}
//路径不存在,返回2
else
{
return 2;
}
}
/*---------------------------------------------------------*/


/*---------------------------------------------------------*
 * 函 数 名:FAT32ReadFileX
 * 隶属模块:FAT32文件系统
 * 函数功能:读取MP3文件放到vs1003中播放出来
 * 输入变量:*pfi,指向存储文件信息的结构体;len:读取文件的长度;(*pfun)(UINT8):调用的指针函数
 * 全局变量:FAT32Buffer,pArgpArg指针指向Init_Arg_UDISK全局结构体,
 * 调用函数:
 * 返 回 值:读取数据的len
 * 说    明:
 *---------------------------------------------------------*/
UINT32 FAT32ReadFileX(struct FileInfoStruct *pfi, UINT32 len, void (*pfun)(UINT8))
{
UINT32 i,j,k;   //i,读取的簇号;j,读取的扇区号,k,读取的字节号
UINT32 leftsector; //未读取的簇数
UINT32 leftcluster; //未读取的扇区数
UINT32 leftbyte; //未读取的字节数
UINT32 counter = 0; //对以读取的数据进行统计,一旦达到len个,则退出函数
//init the struct of pfi
pfi -> FileCurOffset = pfi -> FileStartCluster;
pfi -> FileCurSector = SOC(pfi -> FileCurCluster);
pfi -> FileCurPos    = 0;
pfi -> FileCurOffset = 0; 


//注:任何一个文件在存储的时候,总是一个新的簇开始的,但是此函数允许我们读文件的时候,不是从文件的第一个字节读取,而是可以定位偏差的,
//譬如从文件的第offset个数据开始读取,故第一次读取的不是以簇为单位读取。
//1、如果文件大于一个簇,以簇为单位读取数据,第一个簇读完之后;
//2、当剩下的文件不足一簇但足一个扇区,以扇区为单位读数据;
//3.最后当剩余数据不足一个扇区,以字节为单位读取数据



//读取整簇数据,以簇为单位读取数据,temp= 还需要读取簇的个数
leftcluster = (len - counter) / (pArg -> BytesPerSector * pArg -> SectorsPerCluster);
for(i = 0 ; i < leftcluster; i++)   //以簇为单位读取数据
{
//pfi -> FileCurCluster =FAT32GetNextCluster(pfi -> FileCurCluster);
FAT32ReadSector(pfi -> FileCurSector, FAT32Buffer);
for(j = SOC(pfi -> FileCurCluster); j < SOC(pfi -> FileCurCluster) + pArg -> SectorsPerCluster; j++)
{
FAT32ReadSector(j, FAT32Buffer);   //读当前文件的当前扇区数据
pfi -> FileCurSector = j; //更新(文件当前扇区)
for(k = 0; k < pArg -> BytesPerSector; k++)
{
if(counter >= len)
{
return len;
}
(*pfun)(FAT32Buffer[k]); //传送数据到vs1003
counter++; //传送的字节数+1
pfi -> FileCurOffset++; //更新(文件在当前扇区偏移量)
pfi -> FileCurPos++; //更新(文件在当前扇区地址
pfi -> FileCurPos %= pArg -> BytesPerSector ;//如果一个扇区读取完后,更新(文件当前扇区地址)
}
}
pfi -> FileCurCluster =FAT32GetNextCluster(pfi -> FileCurCluster); //更新当前文件当前簇
}


//如果剩余数据不足一个簇,而足一个扇区,则以扇区为单位读取数据,更新(文件当前簇)
//文件剩余长度不足一簇,计算还需读取的扇区数
leftsector = SOC(pfi -> FileCurCluster) + (len - counter) / (pArg -> BytesPerSector);
pfi -> FileCurSector=SOC(pfi -> FileCurCluster); //更新(文件当前初始扇区)

//从当前簇的初始扇区开始,依次读取以扇区为单位的数据文件,j代表当前文件所在簇的初始扇区
for(j = SOC(pfi -> FileCurCluster); j < leftsector; j++)
{
FAT32ReadSector(j, FAT32Buffer);
pfi -> FileCurSector = j;
for(k = 0; k < pArg -> BytesPerSector; k++)
{
if(counter >= len)
{
return len;
}
(*pfun)(FAT32Buffer[k]); //传送数据到vs1003
counter++; //传送的字节数+1
pfi -> FileCurOffset++; //更新(文件当前扇区偏移量)
pfi -> FileCurPos++; //更新(文件当前扇区地址)
pfi -> FileCurPos %= pArg -> BytesPerSector ;
}
}

//读取最后一个扇区的数据
leftbyte = len-counter; //数据的剩余长度= 文件的长度-已读取的数据长度
pfi -> FileCurSector = j;
FAT32ReadSector(pfi -> FileCurSector, FAT32Buffer); //读当前文件的当前扇区数据
for(k = 0; k < leftbyte; k++)
{
if(counter >= len)
{
return len;
}
(*pfun)(FAT32Buffer[k]);
counter++;   //读取一个数据,(已读取的数据长度)+ 1
pfi -> FileCurOffset++;
pfi -> FileCurPos++;   //更新(文件在当前扇区地址)
pfi -> FileCurPos %= pArg -> BytesPerSector ;
}
return len;
}
/*---------------------------------------------------------*/

























  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值