更多资料见酷学玩首页:http://www.q-sharewe.com
FATFS浅谈
刚开始看到FATFS时,一头雾水,不知道从何下手,网上也搜了很多
资料,要么高深莫测,要么简单地一笔代过.
断断续续地摸索了一段时间,算是对文件系统有了初步的认识,整
理一下思路,将自己的学习过程,及学习心得写出来与大家分享,文笔
有限,力求简洁易懂,希望对初学者有所帮助,不足之处请指正.
笔者用的是酷学玩summerV1.3的开发板,64M的microSD卡(已
格式化为FAT32格式),底层驱动是yuanyin移植的,如果你用的不是
酷学玩stm32的板子,那也没关系,网上有很多移植的例程,可以参照着
尝试移植;或者根据酷学玩的例程修改也可.
本文主要介绍FATFS的API函数,仅针对初学者入门,高手请拍
砖.
例程中用到的全局变量定义如下:
FATFSfs;//Workarea(filesystemobject)forlogicaldrive
FILfsrc,fdst;//fileobjects
FRESULTres;//FatFsfunctioncommonresultcode
UINTbr,bw;//FileR/Wcount
更多资料见酷学玩首页:http://www.q-sharewe.com
一一一一....注册工作区域注册工作区域注册工作区域注册工作区域
FRESULTf_mount(
BYTEDrive,/Logicaldrivenumber/
FATFSFileSystemObject/Pointertotheworkarea/
);
函数说明:
1.此函数的作用就是在磁盘里注册一个缓冲区域,用来存储FAT32文件系统的一些相关信
息.
2.参数说明:
a)Drive:盘符
b)FileSystemObject:指向缓冲区域的指针
3.对磁盘进行操作之前,这个函数是不可少的
例程:f_mount(0,&fs);
二二二二....打开文件夹打开文件夹打开文件夹打开文件夹
FRESULTf_opendir(
DIRDirObject,/Pointertotheblankdirectoryobject
structure/
constTCHARDirName/Pointertothedirectoryname/
)
函数说明:
1.此函数可以打开一个已存在的文件夹
2.参数说明:
a)DirObject:指向一个空白的结构体,用来存储要打开的文件夹信息
b)DirName:指向该文件夹名称的指针
三三三三....读取文件夹读取文件夹读取文件夹读取文件夹
FRESULTf_readdir(
DIRDirObject,/Pointertotheopendirectoryobject/
FILINFOFileInfo/Pointertothefileinformationstructure/
);
函数说明:
1.此函数按照顺序读取文件夹内文件
2.参数说明:
a)DirObject:指向读取的文件夹的信息结构体的指针
b)FileInfo:指向文件信息结构体,用来存储读取到的文件的信息
3.重复调用此函数可读取文件夹内所有文件
4.当所有文件读取结束,函数返回一个空字符串到f_name[]中
5.如果一个空指针赋给FileInfo,将返回从第一个文件开始读取.
更多资料见酷学玩首页:http://www.q-sharewe.com
例程:这段程序先打开文件夹folde/move,然后查找其中的存档文件,并通过串口输出
读取的文件名
if(f_opendir(&dirs,"folder/move")==FR_OK)//打开文件夹
{
while(f_readdir(&dirs,&finfo)==FR_OK)//按照顺序读文件夹
{
if(!finfo.fname[0])break;//如果文件名为0,结束
{
if(finfo.fattrib==AM_ARC)//判断文件属性
Debug("文件名:%s\r\n",finfo.fname);
}
}
}
串口输出如下:
在PC上查看SD卡:
可以看到,程序输出了后面三个文件的名称,对文件夹没作处理,因为在程序里
对文件属性进行了判断:
if(finfo.fattrib==AM_ARC),意思是只对存档文件进行处理;
至于什么是存档文件,以下是在百度知道搜到的结果:
视窗系统中文件属性有四种类型,我来告诉你这四种类型是什么意思:
只读-表示该文件不能被修改
隐藏-表示该文件在系统中是隐藏的,在默认情况下用户不能看见这些文件。
系统-表示该文件是操作系统的一部分。
存档-表示该文件在上次备份前已经修改过了,一些备份软件在备份系统后会把这些文件默
认的设为存档属性。
存档属性在一般文件管理中意义不大,但是对于频繁的文件批量管理很有帮助。
更多资料见酷学玩首页:http://www.q-sharewe.com
四四四四....打开打开打开打开\新建一个文件新建一个文件新建一个文件新建一个文件:
FRESULTf_open(
FILFileObject,/Pointertotheblankfileobjectstructure
/
constTCHARFileName,/Pointertothefileneme/
BYTEModeFlags/Modeflags/
);
函数说明:
1.此函数可以打开,或新建一个文件
2.参数说明
a)FileObject:指向一个用来存储文件对象的空结构体的指针
b)FileName:指向文件名的指针
c)ModeFlags:打开方式,可以是以下一种或几种的组合(默认方式是
FA_OPEN_EXISTING)
ValueDescription
FA_READ读模式,(读写模式可同时生效)
FA_WRITE写模式,(读写模式可同时生效)
FA_OPEN_EXISTING默认打开方式
FA_OPEN_ALWAYS打开文件,如果文件不存在,则创建一个新文件;用此种方式,可以用f_lseek在文件后追加数据
FA_CREATE_NEW新建文件,如果文件已存在,则新建失败
FA_CREATE_ALWAYS新建文件,如果文件已存在,覆盖旧文件
五五五五....读取文件读取文件读取文件读取文件::::
FRESULTf_read(
FILFileObject,/Pointertothefileobjectstructure/
voidBuffer,/Pointertothebuffertostorereaddata/
UINTByteToRead,/Numberofbytestoread/
UINTByteRead/Pointertothevariabletoreturnnumberofbytes
read/
);
函数说明:
1.这个函数可以读取文件的内容
2.参数说明:
a)FileObject:指向文件对象结构体的指针
b)Buffer:指向存储读取到的数据的缓冲的指针
c)ByteToRead:准备读取的字节数
d)ByteRead:
i.它的作用就是用来检测文件的末尾,就是下面例程中的这一句:
if(res||br ii.每次f_read执行完后,ByteRead值等于本次读取到的字节数,若ByteRead
<ByteToRead,即本次读取到的字节小于准备读取的字节,说明读指针已到达
文件末尾.
更多资料见酷学玩首页:http://www.q-sharewe.com
例程:此处参考酷学玩例程,以读取的方式打开文件,然后将文件内容通过串口输出。
res=f_open(&fsrc,"news/news.txt",FA_READ);
if(!res)
{
Debug("opennews/news.txt:%d\r\n",res);
br=1;
a=0;
Debug("文件内容:");
for(;;)
{
for(a=0;a<512;a++)buffer[a]=0;
res=f_read(&fsrc,buffer,sizeof(buffer),&br);
Debug("%s\r\n",buffer);
if(res||br }
}
f_close(&fsrc);//不论是打开,还是新建文件,一定记得关闭
运行后串口输出结果:
下面是在PC中查看:
更多资料见酷学玩首页:http://www.q-sharewe.com
六六六六....写文件写文件写文件写文件::::
FRESULTf_write(
FILFileObject,/Pointertothefileobjectstructure/
constvoidBuffer,/Pointertothedatatobewritten/
UINTByteToWrite,/Numberofbytestowrite/
UINTByteWritten/Pointertothevariabletoreturnnumberof
byteswritten/
);
函数说明:
1.此函数用来向文件中写入数据,前提是以写文件的方式打开文件
2.参数说明:
a)FileObject:指向文件对象结构体的指针
b)Buffer:指向数据缓冲的指针
c)ByteToWrite:准备写入的字节数
d)ByteWritten:记录已写入的字节数,用来检测是否写完
3.后两个参数的长度都是两个字节,计数值最大为65536,所以一次写入字节数最大为
64K。一般情况下一次不会写这么长的数据,因为就算RAM足够用,也不会在里面开一
个几十K的数据缓冲区。
例程:
结合前面的f_open函数,在下面例程中以写的方式新建一个txt文档,然后写入100个字节。
已定义:unsighedcharbuffer[100]="Thisisanewfile,thedataisjustwrittenin!这是一个新
文件,数据也是新的!";
res=f_open(&fsrc,"new/NewText.txt",FA_WRITE|FA_CREATE_ALWAYS);
if(res==FR_OK)
{
Debug("createfileok!\r\n");
Debug("startwrite!\r\n");
do
{
res=f_write(&fsrc,buffer,100,&bw);
if(res)
{
Debug("writeerror:%d\r\n",res);
break;
}
Debug("writeok!\r\n");
}
while(bw<100);//判断是否写完(bw>100,表示写入完成)
}
f_close(&fsrc);//关闭文件,必须和f_open函数成对出现
更多资料见酷学玩首页:http://www.q-sharewe.com
运行后串口输出:
下面为PC中查看结果:
掌握以上几个函数后掌握以上几个函数后掌握以上几个函数后掌握以上几个函数后,,,,可以可以可以可以利用利用利用利用FATFS对对对对SDSDSDSD卡卡卡卡进行进行进行进行基本的读写基本的读写基本的读写基本的读写操操操操
作作作作了了了了。。。。
下面介绍另外几个常用的函数下面介绍另外几个常用的函数下面介绍另外几个常用的函数下面介绍另外几个常用的函数。。。。
更多资料见酷学玩首页:http://www.q-sharewe.com
七七七七....移动文件指针移动文件指针移动文件指针移动文件指针::::
FRESULTf_lseek(
FILFileObject,/Pointertothefileobjectstructure/
DWORDOffset/Fileoffsetinunitofbyte/
);
函数说明:
1.此函数在对已打开的文件进行读或写时,可以移动当前指针位置
2.参数说明:
a)FileObject:指向文件对象结构体的指针
b)Offset:指针移动的长度
例程:
参考官网作者公布的例程,本例以前文中new/news.txt文件为基础
res=f_open(&fsrc,"news/news.txt",FA_WRITE);
res=f_lseek(&fsrc,500);////指针指向第500个字节
res=f_write(&fsrc,"500",3,&bw);
res=f_lseek(&fsrc,fsrc.fptr+100);////指针向前移动100个字节
res=f_write(&fsrc,"forward",8,&bw);
res=f_lseek(&fsrc,fsrc.fptr-200);////指针向后移动200个字节
res=f_write(&fsrc,"backward",9,&bw);
res=f_lseek(&fsrc,fsrc.fsize);////指针指向文件末尾
res=f_write(&fsrc,"end",3,&bw);
res=f_close(&fsrc);
运行后在PC中查看结果:红色部分为笔者注.
更多资料见酷学玩首页:http://www.q-sharewe.com
八八八八....截断文件截断文件截断文件截断文件::::
FRESULTf_truncate(
FILFileObject/Pointertothefileobject/
);
函数说明:
1.此函数可以在将文件在当前指针处截断
2.参数说明:
a)FileObject:指向文件对象结构体的指针
3.此函数可以截断文件,也可以延长文件长度
例程:以上节news/news.txt为基础,本段程序可将文件在指定长度处截断
res=f_open(&fsrc,"news/news.txt",FA_WRITE);
res=f_lseek(&fsrc,60);////指针指向第60个字节
res=f_truncate(&fsrc);////将文件在此截断
res=f_sync(&fsrc);////关闭文件
上图为运行程序之前在PC上查看
下图为运行程序之后,,从右面文件夹中可以看出,文件大小变成了60个字节.
更多资料见酷学玩首页:http://www.q-sharewe.com
九九九九....刷新缓存信息刷新缓存信息刷新缓存信息刷新缓存信息::::
FRESULTf_sync(
FILFileObject/Pointertothefileobject/
);
函数说明:
1.此函数功能兼容f_close,它于f_close的区别就是执行后,当前文件是否仍然有效.
2.参数说明:
a)FileObject:指向文件对象结构体的指针
3.调用此函数后,当前文件仍然可读可写可查询.
4.当文件处于长时间的写模式,如数据记录时,定期调用此函数,或在写入数据后立即调用
此函数,可以减少因断电等意外情况带来的损失.有点WORD中后台定期保存的意思.
十十十十....新建文件夹新建文件夹新建文件夹新建文件夹::::
FRESULTf_mkdir(
constTCHARDirName/Pointertothedirectoryname/
);
函数说明:
1.新建一个文件夹
2.参数说明:
a)DirName:指向将要创建的文件夹名的指针
3.文件名应符合fatfs标准,不能包含非法字符,
4.若不支持长文件名,文件名长度不能大于8,否则新建不成功
5.例程:
a)f_mkdir("new");
b)f_mkdir("folder/new");
十一十一十一十一....删除文件删除文件删除文件删除文件或文件夹或文件夹或文件夹或文件夹::::
FRESULTf_unlink(
constTCHARFileName/Pointertotheobjectname/
);
函数说明:
1.此函数可以删除一个文件或文件夹
2.参数说明:
a)FileName:指向文件或文件夹的名称的指针
3.删除文件夹时:
a)不能为当前文件夹
b)不能为非空文件夹
4.删除文件时
a)不能为已打开文件
b)不能为只读文件
更多资料见酷学玩首页:http://www.q-sharewe.com
十二十二十二十二....重命名重命名重命名重命名\移动文件移动文件移动文件移动文件或文件夹或文件夹或文件夹或文件夹
FRESULTf_rename(
constTCHAROldName,/Pointertooldobjectname/
constTCHARNewName/Pointertonewobjectname/
);
函数说明:
1.此函数可以移动或重命名一个文件或文件夹
2.参数说明:
a)OldName:指向旧文件名的指针
b)NewName:指向新文件名的指针
3.此函数可重命名文件或文件夹,而不论文件夹是否为空
4.此函数可移动文件或文件夹,而不论文件夹是否为空
例程:
res=f_rename("folder/old.txt","folder/newname.txt");//重命名文件,
res=f_rename("folder/123.txt","new/456.txt");//将文件夹folder中的123.txt文件,移动到文件
夹new中并重命名为456.txt
更多资料见酷学玩首页:http://www.q-sharewe.com
十三十三十三十三....获取文件信息获取文件信息获取文件信息获取文件信息
FRESULTf_stat(
constTCHARFileName,/Pointertothefileordirectoryname/
FILINFOFileInfo/PointertotheFILINFOstructure/
);
函数说明:
1.此函数可以获取文件的最近修改时间,属性等信息,获取的信息存在fileinfo结构体中
2.参数说明:
a)FileName:指向文件名的指针
b)FileInfo:指向保存文件信息的结构体的指针
3.如果目标是文件夹,获取的大小为0.
4.此函数对根目录无效
5.时间和日期均为两个字节,存储格式如下
a)日期:
i.bit15…bit9:年减去1980
ii.bit8…bit5:月
iii.bit4…bit0:日
b)时间:
i.bit15…bit11:时
ii.bit10…bit5:分
iii.bit4…bit0:秒除以2
c)如
i.日期:0000001000100001,表示1981年1月1日
ii.时间:0000100000100001,表示1点1分2秒
例:
res=f_stat("folder/newname.txt",&finfo);//读取folder目录下newname.txt文件的信息
if(res)
Debug("newname.txterr:%d\r\n",res);
else
{
Debug("newname.txtsize:%lu\r\n",finfo.fsize);
Debug("fdate:%d\r\n",finfo.fdate);
Debug("ftime:%d\r\n",finfo.ftime);
Debug("fattrib:%d\r\n",finfo.fattrib);
}
更多资料见酷学玩首页:http://www.q-sharewe.com
串口输出结果:(红色部分为笔者注)
结果分析:
newname.txtsize:500:表示该文件的长度为500个字节
fdata:15685:修改日期,转化成2进制:0011110101000101
按照日期储存格式,应该是2010年10月5日
Ftime:36278:修改时间,转化成2进制:1000110110110110
按照时间存储格式,应该是17点45分44秒
Fattrib:36:文件属性,按照FATFS中定义,如下图:
36应该是AM_ARC|AM_SYS,即存档文件和系统文件
(原文见Ff.h)
以下为PC中右击属性查看的结果:
与串读出结果一致.
更多资料见酷学玩首页:http://www.q-sharewe.com
十四十四十四十四....改变改变改变改变文件文件文件文件属性属性属性属性:
FRESULTf_chmod(
constTCHARFileName,/Pointertothefileordirectory/
BYTEAttribute,/Attributeflags/
BYTEAttributeMask/Attributemasks/
);
函数说明:
1.此函数可以修改文件或文件夹的属性
2.可修改的属性只能是以下一种或几种的组合,对其它属性无效
AttributeDescription
AM_RDOReadonly
AM_ARCArchive
AM_SYSSystem
AM_HIDHidden
3.参数说明:
a)Filename:指向文件或文件夹的名称的指针
b)Attribute:要置位的属性
c)AttributeMask:需要改变的属性(包括要置位的和要清除的属性)
4.使用方法:
a)Attribute须为AttributeMask的子集
b)函数对AttributeMask中的属性集合进行处理,若属性包含在Attribute
中,则置位,否则清除
例程:
1.对文件newname.txt,置位ARC和SYS属性,取消HID和REO属性
res=f_chmod("folder/newname.txt",AM_ARC|AM_SYS,AM_ARC|AM_RDO|AM_HID|
AM_SYS);
if(res)
Debug("err:%d\r\n",res);
else
{
res=f_stat("folder/newname.txt",&finfo);
Debug("%d\r\n",finfo.fattrib);
}
2.对文件夹new,置位SYS和ARC属性,取消HID和RDO属性
res=f_chmod("new",AM_SYS|AM_ARC,AM_ARC|AM_RDO|AM_HID|AM_SYS);
if(res)
Debug("err:%d\r\n",res);
else
{
res=f_stat("new",&finfo);
Debug("%d\r\n",finfo.fattrib);
}
更多资料见酷学玩首页:http://www.q-sharewe.com
十五十五十五十五....改变文件时间戳改变文件时间戳改变文件时间戳改变文件时间戳
FRESULTf_utime(
constTCHARFileName,/Pointertothefileordirectorypath/
constFILINFOTimeDate/Timeanddatatobeset/
);
函数说明:
1.此函数可以更改文件的最近修改时间
2.参数说明:
a)Filename:指向文件的指针
b)Timedate:指向文件信息结构体的指针
3.使用方法:
作者在官网中公布了另外一个函数set_timestamp,在这个函数里,可以我们可以写入常
规的日期时间,然后此函数按日期存储格式(见前文)将数据整合后调用f_utime.
例:
FRESULTset_timestamp(charobj,/Pointertothefilename/
intyear,intmonth,intmday,inthour,intmin,intsec
)//
{
FILINFOfno;
fno.fdate=(WORD)(((year-1980)512U)|month32U|mday);
fno.ftime=(WORD)(hour2048U|min32U|sec/2U);
returnf_utime(obj,&fno);
}
res=set_timestamp("123.txt",2001,06,05,02,03,34);//修改123.txt时间
Debug("%d\r\n",res);
‘
执行函数后,串口返回0
在PC上右键属性可以看到结果如下:
更多资料见酷学玩首页:http://www.q-sharewe.com
先写到这,后面的函数,用到时再研究:
?f_forward-Forwardfiledatatothestreamdirectly
?f_chdir-Changecurrentdirectory
?f_chdrive-Changecurrentdrive
?f_getcwd-Retrievethecurrentdirectory
?f_gets-Readastring
?f_putc-Writeacharacter
?f_puts-Writeastring
?f_printf-Writeaformattedstring
嵌入式之路还很长,写下此文,与读者共勉.如有疑问,请联系笔者,共同交流,谢谢.
邮箱:tao3236@126.com
|
|