1. 总则
本文件系统完全兼容FAT16/FAT32文件系统总共两种格式,兼容长文件名,兼容文字编码GB2312/UNICODE汉字编码(文件名完全支持中文),实现了支持子目录,实现了支持文件的读取,写入,删除,创建等文件系统常用功能。总之,本文件系统代码全部使用C代码编写,可以移植去各种单片机平台上面实现文件系统模块。 2. 文件系统支持路径字符串的原则 1) 盘符原则 a) 盘符原则,盘符命名由C开始,到Z结束 2) 文件名原则(长文件名的长度不超过250字符的字节) a) 文件名可是文件名与扩展名混合组成, 1)短文件名不要超过8个字节,长文件名不要超过250字节 2)扩展名一般不要超过3个字节 b) 文件名首字符不要为数字 c) 文件名的字符串大小写不作区分 3. 文件系统功能论据 1) 该文件系统完全兼容FAT16/FAT32文件系统总共两种格式,兼容长文件名,兼容文字编码GB2312/UNICODE汉字编码(文件名完全支持中文),实现了支持子目录,实现了支持文件的读取,写入,删除,创建等文件系统常用功能。 2) 本文件系统代码全部使用C代码编写,代码可以移植去各种单片机平台上面实现文件系统模块运行。在单片机上运行程序员要把磁盘虚拟驱动替换为SD卡或者磁盘驱动。 3) 本文件系统代码实现了文件读写缓冲:文件内存缓冲越大,文件读写越快,其大小可以用编译宏EnableFileBuf,TotalFileBUFsQTYeachFCB,FileBUFSize来设置(在配置文件fat_cfg.h中)。 4. 文件系统源代码文件说明举例 1) fat.c—文件系统代码 2) fat.h—文件系统函数声明文件 3) Fat_cfg.h—配置文件文件系统 4) Types.h—文件系统数据类型重替换的文件 5) Flash_management.c—磁盘虚拟驱动 6) Time.c—RTC实时时钟的驱动文件,文件存储,修改,创建时间提供
5. 文件系统重要占用内存数据结构(仅供参考,实际情况请参考配置文件fat_cfg.h) 1) 分区数据结构—支持FAT16/FAT32 structpartition_BPB{ charpartition_id; //从C开始到Z结束 char system_id;//分区类型 0C-FAT32,06-FAT16 ect.. long relative_sector;//分区起始扇区号 longtotal_sector; //分区总扇区数 intbytes_per_sector;//每扇区字节数 charsector_per_cluster; //每簇扇区数 int reservedsector; //保留扇区数 charnumbers_of_FAT;//FAT副本数 intboot_entries;//根目录项数,供FAT12/16使用 intsmall_sector; //小扇区簇 charmedia_descriptor; //媒体描述符 intsectors_per_FAT; //每FAT扇区数,供FAT12/16使用 intsectors_per_track; //每道扇区数 intnumber_of_head; //磁头数 longhidden_sectors; //隐藏扇区数 longlarge_sector;//总扇区数,包含FAT32总扇区数 longsector_per_FAT32;//每FAT扇区数,供FAT32使用 int extended flag;// 扩展标志,供FAT32使用 intfile_system_version; //文件系统版本 longroot_cluster_number;//根目录簇号 intfile_system_information_sectornumber; //文件系统信息扇区号 intcopy_of_boot_sector;//备份引导扇区 char reserved[12];//保留,,供FAT32使用 }; 2) 文件数据结构—支持FAT16/FAT32 struct file_{ charfilename[256];//支持长文件名 charfile_extention[3]; //文件扩展名 charfile_attribute;//属性 char reserved; charcreate_time_10ms;//创建时间的10毫秒位 intfile_created_time;//文件创建时间 intfile_created_date;//文件创建日期 intlast_access_date;//文件最后访问日期 intfirst_cluster_number_high2bytes; //文件首簇号高16位 intrecent_modified_time;//文件最近修改时间 intrecent_modified_data;//文件最近修改日期 intfirst_cluster_number_low2bytes; //文件首簇号低16位 longfile_length;//文件长度 3) Core数据结构 struct core_{ current_folder[256];//存放当前目录 charfile_openned_flag;//标记struct file_已打开 } 6. 文件系统API函数 1. 自动格式化FAT16/32函数FAT16_filesystem_autoformat()—该函数由系统U盘启动时可调用并运行,它首先会读取U盘 0扇区MBR,判断MBR有效标记是否为0x55aa,如果MBR有效标记不为0x55aa,该函数将把U盘自动格式化为FAT16或FAT32文件系统;起用自动格式化处理,U盘上原有的数据被迫丢失,因此以安全层面考虑,建议不用此函数。
2. FAT文件系统初始化必须函数char FAT_filesystem_initialiation()—该函数是在U盘启动时调用,是文件系统初始化必须调用的函数,它将U盘中默认的几个分区的信息读入struct partition_BPB中,并初始化struct CORE。
3. 建立文件函数u8 create_file(u8 * filename)—该函数调用可在u盘上建立一个文件,文件名和路径通过参数char *filename指定;
4. 目录建立函数u8 create_floder(u8 * foldername)—该函数调用可在u盘上建立一个目录,目录名和路径通过参数char *foldername指定; 5. 重命名文件函数u8 rename_file(u8 * oldfilename,u8 * newfilename)—该函数用于U盘上的一个文件重命名,原文件由参数u8 * oldfilename指定,新文件名由参数u8* newfilename指定;
6. 打开文件函数u8 open_file(u8 * filename)—该函数用于在U盘上的打开一个文件,文件名通过参数u8 * filename指定,打开文件成功,返回值为文件操作句柄FCBsn(FCB sequential number),或0xff—打开文件错误,在打开错误情况下,建议先使用close_file关闭一个打开的文件后再执行打开文件。
7. 关闭文件函数u8 close_file(u8 FCBsn)—该函数调用关闭一个已打开的文件,并释放文件占用的文件句柄,文件句柄由FCBsn指定。 8. 改变当前目录函数u8cd_folder(u8 * foldername,u8 mode)—该函数用于改变文件系统的当前目录,目录改变至由参数u8 * foldername指定。函数并有两种的模式各为:1)参数mode= 0:--进入目录;2)参数mode=1--返回上层目录。
9. 文件读写位置定位函数u8 f_seek(u8FCBsn, s32 offset, u8 origin)—该函数用于文件读写当前位置的设定定位;FCBsn –是需要操作文件的文件打开句柄;offset--相对origin起始外位置偏移量;origin 指定位置移动的起始外位置,其起始外位置共有三个: SEEK_SET(0) 文件开始位置SEEK_CUR(1) 文件当前位置SEEK_END(2) 文件结束位置。 10. 文件读取函数u16 read_file(u8 FCBsn,8* buffer, u16length)—该函数用于打开的文件当前位置去读取一个指定的长度的一串数据,读取数据将存放在缓冲区buffer内,读取数据长度可由参数u16 length指定,缓冲区的首地址可由参数u8 * buffer指定,该函数返回是读取成功的总共字节数; 11. 文件写入函数u16 write_file(u8 FCBsn,u8* buffer, u16length)- 该函数实现将缓冲区buffer内的指定长度的数据去写入一个打开文件的当前位置,,写入数据长度由参数u16length指定,缓冲区首地址由参数char* buffer指定,函数返回值为成功写入的数据字节数; 12. 目录遍历函数u8 folder_enumeration(u8 *return_string,u8mode,u8 *ATTR)—该函数用于遍历u盘当前目录下所有的文件和目录,调用一次将返回一个文件或目录,同时定义了二种遍历模式,mode(0)-调用后将复位到目录的第一个文件或目录重新开始,mode(1)-继续上一次遍历目录项,遍历模式由参数charmode传递,遍历返回的文件项目录名存储于缓冲区中,其首地址由参数u8*return_string指定,返回文件目录项的类型由u8*ATTR传递,其值是返回文件或目录directoryentry的attribute字段;
13. U盘整盘遍历函数u8disk_enumeration(u8 disk_,u8 *return_string,u8 mode,u8* ATTR)—该函数可以用于遍历指定U盘整盘下所有的文件与目录,一次调用返回一个文件或目录,同时定义了二种遍历模式,mode(0)-调用后将复位到目录的第一个文件或目录重新开始遍历,mode(1)-继续上一次遍历的目录项,被枚举磁盘ID(ID编号由0开始,到Maximum_Disks – 1)由参数u8 disk_指定,遍历的模式由参数charmode指定,遍历返回的文件或目录名存储于缓冲区中,其首地址由参数u8 *return_string指定,返回文件目录项的类型由u8 *ATTR传递,其值是返回文件或目录directory entry的attribute字段; 文件系统遍历算法使用专利的《深度优先算法》。 14. 删除文件函数-- u8 delete_file(u8 *filename)—该函数用于删除U盘上的一个文件,删除的文件名通过参数char*filename指定。
15. 删除目录函数-- u8 delete_folder(u8 * foldername)—该函数用于删除u盘上的一个目录,删除目录名通过参数u8 *foldername指定,被删除目录必须是空的目录; 16. 文件查找函数—u8 find_file(u8 * filename,u8 mode, u8* folder_name )—查找文件函数支持2种模式:1)mode = 0:当前目录下查找;2)mode=1:在U盘内查找;查找文件名通过参数char * filename指定,查找模式通过参数u8 mode指定,查找成功后文件名加上其所在目录的完整路径名的字符串通过参数folder_name返回。 17. 查询分区容量和剩余容量函数—u8 volume_inquiry(u8 partition_id,u32 *volume_capacity, u32 *volume_free_space);—该函数用来查询可指定分区分区容量和剩余空间,分区号请通过参数u8partition_id指定,查询结果的分区容量将存入在参数u32 *volume_capacity,查询结果的剩余容量将存入在参数u32 *volume_free_space。 7. 例程 1)使用volume_inquiry(),获取分区容量和分区剩余容量 volume_inquiry('c',&cc,&bb); printf("Volume C Capacity: %ld\n",cc); printf("Volume C FreeSpace: %ld\n",bb);
2)在当前目录{C:\\}之下建立目录:CREATE_FOLDER_TEST create_floder("CREATE_FOLDER_TEST");
3)在目录CREATE_FOLDER_TEST之下建立文件:created_file.txt create_file("C:\\CREATE_FOLDER_TEST\\created_file.txt");
4)进入目录d:\\CREATE_FOLDER_TEST,并打印目录d:\\CREATE_FOLDER_TEST的所有文件! cd_folder("d:\\CREATE_FOLDER_TEST",0); mode = 0; while(folder_enumeration(buf,mode,&ATTR) == SUCC) { printf("\nreaded entry=%s Attr = %x",buf,ATTR); mode = 1; }
5)返回根目录,并打印根目录下的所有文件 cd_folder(" ",1); mode = 0; while(folder_enumeration(buf,mode,&ATTR) == SUCC) { printf("\nreaded entry=%s Attr = %x",buf,ATTR); mode = 1; } 6)DISK0 被 拷贝至DISK1 mode = 0; //设置disk_enumeration列举mode(0)-复位至第一个文件项或目录项开始枚举 while(disk_enumeration(0,buf,mode,&ATTR)== SUCC) //枚举一个目录项或目录项 { printf("\nreaded entry=%s Attr =%x",buf,ATTR); //打印被枚举的一个目录项或目录项 if(mode == 0) mode = 1;//设置disk_enumeration列举mode(1)- 继续上一枚举后的目录项或目录项 if(ATTR & ATTR_DIRECTORY) { buf[0]++; //盘符由C加1,成为D create_floder(buf); //建一个disk_enumeration的目录 continue; } else //复制文件 { HANDLE1 = open_file(buf); //打开文件 buf[0]++; //盘符由C加1,成为D create_file(buf); //在DISK1上建立文件, } if (HANDLE1 != FAIL) {HANDLE2 = open_file(buf); //打开DISK1上建立的文件 do{ //复制文件 cc = read_file(HANDLE1,buf+400,50000); //读文件 printf("\nreaded chars = %ld",cc); //打印读文件读取的字节数 write_file(HANDLE2,buf+400,cc); //将读取的字节写去DISK1上的文件 if(cc != 50000) //检查读取的字节数,确认文件尾 { close_file(HANDLE1); //文件复制结束,关闭文件 close_file(HANDLE2); break; } }while(1); } else { printf("Openfile failed!"); } } { printf("Openfile failed!"); } }
|