⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 复件 exfuns.c

📁 stm32 红外万年历
💻 C
字号:
#include "exfuns.h"
#include "fattester.h"	
 

///////////////////////////////公共文件区////////////////////////////////////////////
FATFS fs[2];  		//逻辑磁盘工作区.	 
FIL file;	  		//文件1
FIL ftemp;	  		//文件2.
UINT br,bw;			//读写变量
FILINFO fileinfo;	//文件信息
DIR dir;  			//目录

u8 fatbuf[512];//SD卡数据缓存区
///////////////////////////////////////////////////////////////////////////////////////


FIL *fc_src=&file;	//源文件
FIL *fc_dst=&ftemp;	//目标文件
u8 *fc_buf=fatbuf;	//数据缓存区  

//文件名及路径管理器
struct _m_pfnmg pfnmg=
{
	pfnmg_init,
	pfnmg_dir_opendir,
	pfnmg_get_pname,
	pfnmg_get_plfname,
	pfnmg_get_lfname,
	pfnmg_get_ifname,
	pfnmg_scan_folder,
	0,
	0,
	0,
	0,
	0,
	0,	
};

//初始化路径
//不能以'/'结尾!
//path:路径;
//返回值:0,OK;其他,失败.
u8 pfnmg_init(u8*path)
{
	u8 res;
	res=f_opendir(&dir,(const TCHAR*)path);
	if(res)return res;//此路径非法
	else
	{										  
		pfnmg.cftp=0XFF; 	//当前为路径
		pfnmg.foldernum=0; 	//总文件数归零
		pfnmg.dfnum=0;	   	//目标文件数归零
		pfnmg.fttblsize=0; 	//目标文件类型表清空
		f_strcpy(pfnmg.plfname,path);//路径复制给pname	
	}
	return 0;
}
//打开当前目录下的某个文件夹.
//dirname:文件夹名字
//返回值:0,成功;其他,失败;
u8 pfnmg_dir_opendir(u8*dirname)
{
	u8 res;
	u8 len;
	u8 deep;						   					    
	res=f_opendir(&dir,(const TCHAR*)dirname);//打开此文件夹
	if(res==0)//路径OK
	{
		len=f_strlen(dirname); 
		if(dirname[len-1]=='.'&&dirname[len-2]=='.')//回到上一层目录.
		{	    
			deep=f_getdirdeep(dirname);//得到目录深度
			if(deep)//还不是根目录
			{
				if(deep>1)deep--;						//得到上两层的目录
				f_getdirstr(dirname,dirname,deep-1); //得到上一层目录	
			}else dirname[len-2]=0;//添加结束符.	 
		}
		f_strcpy(pfnmg.plfname,dirname);//复制路径
 		pfnmg.cftp=0XFF; 	//当前为路径
		pfnmg.foldernum=0; 	//总文件数归零
		pfnmg.dfnum=0;	   	//目标文件数归零
		pfnmg_scan_folder();//扫描这个新文件夹.
	}
	return res;		
}

//得到当前路径名
u8* pfnmg_get_pname(void) 
{
	u8 len;
	if(pfnmg.cftp!=0XFF)//当前不完全是路径名
	{
		len=f_strlen(pfnmg.plfname);
		while(pfnmg.plfname[len]!='/')len--;
		pfnmg.plfname[len]='\0';//加结束符.
		pfnmg.cftp=0XFF;//当前是路径
	} 
	return pfnmg.plfname;
}   
//得到某个文件名的带路径后的名字
//返回值:路径文件名首地址.
u8* pfnmg_get_plfname(void)
{										  		 
 	return pfnmg.plfname;		    
}
//得到文件名
//返回值:文件名首地址.
u8* pfnmg_get_lfname(void)
{
	u8 len;
	if(pfnmg.cftp==0XFF)return 0;//当前完全是路径名
	else
	{
		len=f_strlen(pfnmg.plfname);
		while(pfnmg.plfname[len]!='/')len--; 
		return pfnmg.plfname+len+1;//返回文件名  
	} 							    
}   
//得到指定编号文件的文件名 编号:0~dfnum+foldernum-1
//index:文件编号(包含了文件夹)
//*ftpt:类型表.
//num:类型数
//返回值:该文件的文件名.
u8* pfnmg_get_ifname(u16 index)
{
	FILINFO finfo;
	u16 i=0;
	u8 t,ftype;
	u8 res;
	u8 tlfname[100];//100个字节用于存放长文件名
	u8 *plfname;

	plfname=pfnmg_get_pname();//得到当前路径名    
	res=f_opendir(&dir,(const TCHAR*)plfname);//打开当前目录
    finfo.lfsize=0;//不使用长文件名 
	if(res==FR_OK)
	{
		if(index<pfnmg.foldernum)//是文件夹区
		{
			for(i=0;i<index+1;)
			{	 
				if(i==index)//已经等于当前要找的文件了.使用长文件名.
				{
					finfo.lfname=(TCHAR*)tlfname;		//长文件名缓存
					finfo.lfsize=sizeof(tlfname);		//缓存大小
				}
				res=f_readdir(&dir,&finfo);	//读取一个文件的信息
		    	if(res!=FR_OK||finfo.fname[0]==0)break;//出错,或者已经读完了
				if(finfo.fattrib&AM_DIR)
				{
					if(finfo.fname[0]=='.'&&finfo.fname[1]=='\0')continue;//不计算"."文件夹
					i++;
				}										    
			}   
		}else //在有效文件区
		{
			index-=pfnmg.foldernum;//实际文件的偏移
			for(i=0;i<index+1;)
			{	 
				if(i==index)//已经等于当前要找的文件了.使用长文件名.
				{
					finfo.lfname=(TCHAR*)tlfname;		//长文件名缓存
					finfo.lfsize=sizeof(tlfname);		//缓存大小
				}
				res=f_readdir(&dir,&finfo);	//读取一个文件的信息
		    	if(res!=FR_OK||finfo.fname[0]==0)break;//出错,或者已经读完了
				ftype=f_typetell((u8*)finfo.fname);//得到文件类型
				for(t=0;t<pfnmg.fttblsize;t++)if(pfnmg.fttbl[t]==ftype)break;
				if(t!=pfnmg.fttblsize)i++;//找到一个符合条件的.
 				   									    
			}
		}
		if(res==FR_OK&&finfo.fname[0]!=0)//成功读取了.
		{				    
			f_stradd(pfnmg.plfname,"/");
			if(*finfo.lfname)f_stradd(pfnmg.plfname,(u8*)finfo.lfname);	//存在长文件名
			else f_stradd(pfnmg.plfname,(u8*)finfo.fname);			   	//拷贝短文件名
			if(finfo.fattrib&AM_DIR)pfnmg.cftp=T_FOLDER;		  		//是个文件夹.	 
			else pfnmg.cftp=f_typetell((u8*)finfo.fname);		  		//目标文件
		}  
	}
 	return pfnmg_get_lfname();//返回得到的文件名.	
}   
//扫描文件夹
//ftpt:文件类型数组
//num:文件类型数
//返回值:文件个数(包括文件夹)
u16 pfnmg_scan_folder(void)
{
	u16 fcnt;  
	u8 i;
	u8 *pname; 

	pname=pfnmg_get_pname();		//得到路径名
	fcnt=f_getfoldernum(pname);		//得到当前文件夹下,文件夹的个数 
	pfnmg.foldernum=fcnt;			//目录个数
	for(i=0;i<pfnmg.fttblsize;i++)	//得到目标文件的个数
	{
		fcnt+=f_getfilenum(pname,pfnmg.fttbl[i]); 
	} 
 	pfnmg.dfnum=fcnt-pfnmg.foldernum;//目标文件的个数
	return fcnt;	
}    		  

//复制字符串.
//将str2的内容,复制到str1里面.
//返回值:0,成功;其他失败.
void f_strcpy(u8*str1,u8*str2)
{				  
	while(*str2!='\0')
	{
		*str1=*str2;
		str1++;		 
		str2++;
	}
	*str1='\0';//末尾加入结束符.  
}	
//得到某个字符串的长度
//str:字符串;
//返回值:长度.
u8 f_strlen(u8*str)
{
	u8 strlen=0;
	while(*str!='\0')
	{
		strlen++;
		str++;
	}
	return strlen;
}					
//对比两个字符串,是否相等.
//相等,返回1;否则,返回0.
u8 f_strcmp(u8*str1,u8 *str2)
{
	while(1)
	{
		if(*str1!=*str2)return 0;//不相等
		if(*str1=='\0')break;//对比完成了.
		str1++;
		str2++;
	}
	return 1;//两个字符串相等
}
//将小写字母转为大写字母,如果是数字,则保持不变.
u8 f_upper(u8 c)
{
	if(c<'A')return c;//数字,保持不变.
	if(c>='a')return c-0x20;//变为大写.
	else return c;//大写,保持不变
}
//将字符串str2添加到str1的后面.	 
u8 f_stradd(u8 *str1,u8 *str2) 
{
	while(*str1!='\0')str1++;
	while(*str2!='\0')
	{
		*str1=*str2;
		str1++;
		str2++;
	}
	*str1='\0';	//末尾添加结束符
	return 0;	//添加成功.
}
//查找某个目录下是否有某个文件
//返回值0,有.其他,没有.
u8 f_find(u8*fpath)
{
	u8 res;
	res=f_open(fc_src,(const TCHAR*)fpath,FA_READ);
	f_close(fc_src);
	return res;		    
}
//复制文件
//fsrc:源文件路径
//fdst:目标文件路径
//func:状态显示函数指针. u32(*prog_func)(u32,u32);,第一个参数为文件大小,第二个参数为当前进行的位置.
//返回值:0,OK,其他,失败.  
u8 f_copy(u8 *fsrc,u8* fdst,prog_funs prog_fun)  
{
	u8 res=0;
	u32 offset=0;
 	res=f_open(fc_src,(const TCHAR*)fsrc,FA_READ);//只读方式打开
	if(res==FR_OK)//成功打开了文件,才开始.
	{   
	 	res=f_open(fc_dst,(const TCHAR*)fdst,FA_WRITE|FA_CREATE_ALWAYS);//新建一个文件
 		while(res==FR_OK)//死循环执行
		{
	 		res=f_read(fc_src,fc_buf,512,&br);	 
			if(res!=FR_OK)break;				//执行错误	  
	 		res=f_write(fc_dst,fc_buf,br,&bw);	//写入 
			if(res!=FR_OK)break;				//执行错误
			if(br!=bw){res=0xff;break;}			//写入错误
			offset+=br;	  
			prog_fun(fc_src->fsize,offset);		//进度显示
			if(br!=512)break;					//读完了.
			f_lseek(fc_src,offset);//偏移到下一次读的地址
		}  
		f_close(fc_dst);
	}
	f_close(fc_src);
	return res;
}
//得到目录的深度
//pathname:路径名
//返回值:0,第一级目录(根目录);1,第二级目录...254,第254级目录
u8 f_getdirdeep(u8*pathname)
{
	u8 dpf=0;
	while(1)
	{
		if(*pathname=='\0')break;//到末尾了
		if(*pathname=='/')dpf++; //找到一个区分符
		pathname++; 		
	}	
	return dpf;
}	   

//得到第几级的目录.
//dsrc:源字符串.(路径)
//ddst:第几级目录字符串(路径)
//deep:0,第一级目录;1,第二级目录...254,第254级目录
//返回值:与deep相等,则成功,0XFF,失败.
u8 f_getdirstr(u8* dsrc,u8 *ddst,u8 deep) 
{
	u8 dpf=0;
	while(1)
	{
		if(*dsrc=='\0')
		{
			if(dpf)dpf--;		//是找到了结束符,而非目录分隔标志.
			break;				//到末尾了	   
		}
		if(*dsrc=='/')			//找到一个区分符
		{
			if(dpf==deep)break;	//目录深度相等了,退出
			dpf++; 				//目录深度增加
		}
		*ddst=*dsrc;			//copy			   
		ddst++;
		dsrc++;
	}
	if(dpf!=deep)return 0XFF;
	else 
	{
		*ddst='\0';//加入结束符.
		return dpf;
	}
}	
		 
const u8 *FILE_TYPE_TAB[4][13]=
{
{"MP1","MP2","MP3","MP4","M4A","3GP","3G2","OGG","ACC","WMA","WAV","MID","FLAC"},
{"LRC","TXT","C","H"},
{"BIN","FON","MP3"},
{"BMP","JPG","JPEG"},
};	    
//报告文件的类型
//fname:文件名
//返回值:文件类型编号.0XFF,表示无法识别.
u8 f_typetell(u8 *fname)
{
	u8 tbuf[5];
	u8 i=0,j;
	while(i<200)
	{
		i++;
		if(*fname=='\0')break;//偏移到了最后了.
		fname++;
	}
	if(i==200)return 0XFF;//错误的字符串.
	fname--;		//最后一个字符的位置
	for(i=0;i<5;i++)//复制后缀名
	{
		tbuf[4-i]=*fname;
		fname--;
	}
	if(tbuf[0]=='.')//后缀名为4个字节
	{
		tbuf[0]=f_upper(tbuf[1]);
		tbuf[1]=f_upper(tbuf[2]);
		tbuf[2]=f_upper(tbuf[3]);
		tbuf[3]=f_upper(tbuf[4]);
		tbuf[4]='\0';//加入结束符
	}else if(tbuf[1]=='.')//3个字节
	{
		tbuf[0]=f_upper(tbuf[2]);
		tbuf[1]=f_upper(tbuf[3]);
		tbuf[2]=f_upper(tbuf[4]);  
		tbuf[3]='\0';//加入结束符
	}else if(tbuf[2]=='.')//2个字节
	{
		tbuf[0]=f_upper(tbuf[3]);
		tbuf[1]=f_upper(tbuf[4]);   
		tbuf[2]='\0';//加入结束符
	}else if(tbuf[3]=='.')//1个字节
	{
		tbuf[0]=f_upper(tbuf[4]);    
		tbuf[1]='\0';//加入结束符
	}else return 0XFF;//未找到后缀名.
	for(i=0;i<4;i++)
	{
		for(j=0;j<13;j++)
		{
			if(*FILE_TYPE_TAB[i][j]==0)break;//此组已经没有可对比的成员了.
			if(f_strcmp((u8 *)FILE_TYPE_TAB[i][j],tbuf))//找到了
			{
				return (i<<4)|j;
			}
		}
	}
	return 0XFF;//没找到
		 			   
}
//得到指定目录下的指定类型文件的个数
u16 f_getfilenum(u8* path,u8 ftype)
{
	u8 res;
	u8 type;
	u16 fnum=0;
	FILINFO finfo;
	res=f_opendir(&dir,(const TCHAR*)path);//打开SD卡上的PICTURE文件夹.
    finfo.lfsize=0;//不使用长文件名 
	if(res==FR_OK)
	{
		while(1)
		{	 
			res=f_readdir(&dir,&finfo);	//读取一个文件的信息
	    	if(res!=FR_OK||finfo.fname[0]==0)break;//出错,或者已经读完了
			type=f_typetell((u8*)finfo.fname);//得到文件类型	 
			if(type==ftype)fnum++;//此类型文件个数增加1.
		}
	}
    return fnum;
}			
//得到指定目录下的文件夹的个数
//包含".."文件夹
u16 f_getfoldernum(u8* path)
{
	u8 res;	    
	u16 fnum=0;
	FILINFO finfo;
	res=f_opendir(&dir,(const TCHAR*)path);//打开SD卡上的PICTURE文件夹.
    finfo.lfsize=0;//不使用长文件名 
	if(res==FR_OK)
	{
		while(1)
		{

			res=f_readdir(&dir,&finfo);	//读取一个文件的信息
	    	if(res!=FR_OK||finfo.fname[0]==0)break;//出错,或者已经读完了
			if(finfo.fattrib&AM_DIR)
			{
				if(finfo.fname[0]=='.'&&finfo.fname[1]=='\0')continue;//不计算"."文件夹
				fnum++;
			}										    
		}
	}
    return fnum;
}									    








⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -