写在前面
之前自己一直在做芯片上应用程序的升级功能,也就是所谓的Bootloader程序,当然,是Secondery Bootloader程序。
在做芯片升级的BootLoader程序时,我的做法计较简单:一般是接收上位机下发的数据,判断数据协议是否正确,判断正确后将数据写入flash。可是,上位机是如何把数据打包发来的,如何按协议组数据帧,如何在一个bin文件中准确定位数据,自己却一致没有机会接触。
偶然的机会需要在掌机上开发对芯片进行升级的功能,由于下位机代码是自己已经写好的BootLoader程序,协议什么的还算是比较熟悉,便就着这个机会接触到了文件操作函数。
本文包含
- 文件指针及文件信息结构
- 文件打开
- 文件关闭
- 文件中数据定位
- 文件删除
- 文件列表菜单显示
文件指针及结构体定义
c语言库中包含了许多对文件操作的函数库,其中对文件指针的定义为
_FILE *FilePointer
_FILE 由c语言库定义好,我们可以直接定义文件指针,用来保存我们需要操作的文件信息。
文件指针是什么?通俗点讲,我们打开一个文件时,需要一个指针指向该文件,但该指针的类型是FILE型的,不恰当的理解可以为指向的是文件名,当然实际上该指针信息包含的不止文件名。
另一个需要定义的是保存查找到的文件信息的结构体,如下:
typedef __packed struct FINDBLK{
U16 num; // 查找到的文件个数
U8 Cur_S;
U8 Index;
S8 name[8]; // 文件名,支持8字节长度,可更改
S8 ext[3];
S8 dir[65]; // 路径
U8 ff_ftime[16]; /* file date_time*/
U32 ff_fsize; /* file size */
S8 ff_name[13]; /* found file name */
U8 ff_attrib; /* attribute found */
}FindBlk;
通过上面的结构体,可以定义一个查找到的文件信息的变量,用来进行文件操作。
文件查找
定义完结构体之后,需要去查找并打开文件,用到 findfirst 和 findnext函数,这两个函数功能如其名。
注意: 在打开文件之前需要把文件关闭,断开文件指针与文件的关系后,重新建立联系。
下面是定义一个文件信息并查找打开文件。
FindBlk fileinfo;
U8 ret;
LCDcls(); //清屏
_fcloseall();//查找打开文件之前关闭所有文件
_setcurdir("D:\\"); //设置查找文件的目录
ret = _findfirst("*.bin",&fileinfo);
// 查找bin文件,用通配符*代替文件名
line = 3;
num = 0;
while(ret==0)
{
strncpy(&name[num][0],&fileinfo.ff_name,sizeof(fileinfo.ff_name));
ret = _findnext(&fileinfo);
num++;// 个数计数器
}
if (num == 0)
{
while (1)
{
myPutString(4,1,"无文件",1);
myPutString(4,2,"按确认返回",1);
if (_bioskey(0) == ENTER)
{
LCDcls();
return;
}
}
}
... ...
上面代码主要是将符合bin格式的文件查找到,并将文件名保存到定义好的name数组中,并用计数器num记录查找到的文件个数。
文件打开与数据定位
查找到文件后,需要打开该文件,也就是重新建立文件指针与文件的关系。通过索引出需要打开的文件的文件名,利用fopen 、 fseek 、filelength 和 fread 函数定位数据。
LCDcls();
_fclose(FilePointer);
FilePointer = _fopen(&name[cn-1][0],"r"); //传入文件名,返回文件指针。
if (FilePointer != 0)
//此处不规范,规范为 != NULL ((void *) 0)
{
filesize = _filelength(FilePointer);
// 传入文件指针,返回该文件的文件长度,字节数。
filesize_ori = filesize;
_fseek(FilePointer,0,0);
// 首先将文件指针定位到 文件的起始位置,起始0偏移0
memset(data_buffer,0,sizeof(data_buffer));
//数据缓存区清零
_fread(data_buffer,filesize,FilePointer);
// 将文件中的数据读取保存到缓冲区中
// filesize--需要读取的长度 FilePointer--文件指针
// 注:每次读取之后,文件指针会自动偏移到读取完的字节后,如读取1024个字节(0-1023),读取后文件指针会指向第1025个字节,即索引为1024的字节。
memset(&data_buffer[filesize],0x1A,(1024*(filesize/1024+1) - filesize));
if (filesize % 1024 != 0)
{
filesize = 1024*(filesize/1024+1);
}
ChooseFile_flag = 1;
while (1)
{
myPutString(4,1,"打开成功",1);
myPutString(4,2,"按确认返回",1);
if (_bioskey(0) == ENTER)
{
LCDcls();
break;
}
}
}
else
{
ChooseFile_flag = 0;
while (1)
{
myPutString(4,1,"打开失败",1);
myPutString(4,2,"按确认返回",1);
if (_bioskey(0) == ENTER)
{
LCDcls();
break;
}
}
}
通过以上操作便完成了文件的打开以及数据的定位读取。
文件删除
文件删除很简单,调用_filedelete即可。
do
{
ret = _filedelete(&name[cn-1][0]);
}while(ret != 0);
LCDcls();
num--;
_filedelete 传入的是需要删除的文件名,返回为结果0或1,当然,在做删除之前需要关闭文件并设置路径。
_fcloseall(); /* 必须先关闭所有文件 */
_setcurdir("D:\\");
一个屏幕显示多文件的小程序
LOOP9:while(1)
{
myPutString(4,1,"--选择删除--",1);
_setdispcolor(1);
if((k!=0)||(fist==0))/* 有按键按下 或第一次执行 */
{
for(i = 0;i < num;i++)
{
if(i == (cn-head))
{
myPutString(4,3+i,&name[cn-1][0],0);
}
else
{
myPutString(4,3+i,&name[i+head-1][0],1);
}
if ((i>=7)||(i>=num))
{
break;
}
}
fist = 1;
k = 0;
}
k = _key_time(100);
if(k==DOWN)
{
cn++;
if (cn > tail)
{
head++;
tail++;
}
Oper_flag = 1;
}
if(k==UP)
{
cn--;
if (cn < head)
{
head--;
tail--;
}
Oper_flag = 1;
}
if(k==ENTER)
{
res = DeleteInfirm();
if (res == 0)
{
break;
}
else
{
LCDcls();
goto LOOP9;
}
}
if(k==ESC)
{
LCDcls();
return;
}
if(cn <= 0)
{
cn = num;
if (num>7)
{
head = num-6;
tail = num;
}
else
{
head = 1;
tail = 7;
}
}
if(cn > num)
{
cn = 1;
head = 1;
tail = 7;
}
}
该程序实现的是在掌机上显示查到的文件名,以列表的形式显示出来。由于屏幕大小的限制,同一屏幕最多显示7个文件,如果文件多余7个,我们需要按上下键来实现文件名的刷新上下移动。这个小程序就是实现这个功能的。