021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结
021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结
上节内容中,初步实现了FatFs文件系统的移植,并且实现了设备的挂载、文件打开/关闭与读写功能,这里对上节遗留的一些问题进行总结,并且继续完善文件系统的一些操作。
一、问题汇总
1、文件名过长
上节例程中,文件名为3:1.txt
,文件打开、读写都没有问题,后来更改了一下文件名为3:TestDomefile.txt
后,文件不能正常打开。
这里需要在ffconf.h中将长文件名支持设置为1
#define _USE_LFN 1 //0:默认设置,不支持长文件名;1:支持长文件名,最长可支持到255个字符。
#define _MAX_LFN 255
关于长文件名设置,可选的设置参数有0-3四种模式
模式 | 说明 |
---|---|
0 | 默认模式,不支持长文件名 |
1 | 模式1,支持长文件名,工作空间存储在BSS(段)中 |
2 | 模式2,支持长文件名,工作空间存储在栈中 |
3 | 模式3,支持长文件名,工作空间存储在堆中 |
这里设置完成后,编译会报如下错误:
.\Objects\YH-429.axf: Error: L6218E: Undefined symbol ff_convert (referred from ff.o).
.\Objects\YH-429.axf: Error: L6218E: Undefined symbol ff_wtoupper (referred from ff.o).
启用长文件支持后,会包含一些操作,这些函数是定义在ccsbsc.c中,这里只需要将ccsbsc.c文件加入工程中即可。
2、无FAT文件系统
当挂载文件系统的时候,可能会出现f_mount
之后返回FR_NO_FILESYSTEM
(13)的情况,这种大概率是FLASH没有格式话造成的,当出现这个情况的时候,就需要堆FLASH进行格式化。具体操作如下:
res = f_mount(&flash_fs,"3:",1); //挂载FLASH,卷标为3,立即挂载
if(res == FR_NO_FILESYSTEM) //若返回值为无FAT文件系统,则进行格式化{res = f_mkfs("3:",0,0); //执行格式化操作,卷标为3,分区规则为0:FDISK,分配单元大小默认为0printf("\r\n磁盘正在格式化中,请稍等.....\r\n");if(res == FR_OK){printf("\r\n磁盘格式化完成...\r\n");f_mount(NULL,"3:",1); //格式化后需要先卸载设备res = f_mount(&flash_fs,"3:",1); //再重新挂载设备}else{printf("\r\n%d磁盘格式化失败,请尝试复位操作!\r\n",res);}}
这里需要注意的是,当使用f_mkfs
格式化FLASH时,需要再fconf.h中先将_USE_MKFS
使能:
#define _USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
这里需要注意三点:
a、之前我已经将FLASH设置为FAT格式,所以测试的时候我将判断是否为是否为FAT文件系统的条件注释掉了,所以每次执行程序都是默认格式化;
b、格式化会将整个芯片全部格式化掉,这里需要注意;
c、格式化完成后,需要先将磁盘卸载,然后重新挂载。
3、文件名中文支持
以上的例程中,我们都是以非中文字符来命名文件,但是后面如果使用中文来命名文件,那可能会出现乱码的情况,例如我们将之前的文件名改为3:FatFs文件系统测试例程.txt
后,用野火提供的外部FLASH模仿U盘例程来看一下创建的文件,会发现是乱码。
遇到这种情况,我们需要将原来工程文件中的ccsbsc.c
文件去掉,将cc936.c文件加入到工程中,并在fconf.h中将_CODE_PAGE更改为936即可。
#define _CODE_PAGE 936
后面如果需要支持繁体中文或者日文等的,可以根据下面的注释去选择编码页,并将对应的编码页加入到工程中即可。
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
*/
二、程序细化
类似于Windows 系统一样,当我们在磁盘上右键属性时,可以看到该磁盘的一些数据信息,这里用FatFs文件系统也可以对FLASH进行这些操作,例如:
1、获取FLASH空间信息
static FRESULT miscellaneous(void)
{FATFS *fs;DWORD fre_clust,fre_sect,tot_sect;printf("\r\n--------------------获取设备信息--------------------\r\n");/* 获取卷3的设备信息 */res = f_getfree("3:",&fre_clust,&fs);if(res){printf("\r\n未获取到设备信息!\r\n");return res;}/* 计算得到的总的扇区个数和空扇区个数 */tot_sect = (fs->n_fatent -2) * fs->csize;fre_sect = fre_clust * fs->csize;/* 打印信息(4096字节/扇区) */printf("》设备总空间:%10lu KB。\n》可用空间::%10lu KB。\n",tot_sect*4 , fre_sect*4);return res;
}
2、文件定位操作
printf("\r\n--------------------文件定位操作--------------------\r\n");res = f_open(&fp,"3:FatFs文件系统测试例程.txt",FA_OPEN_EXISTING | FA_READ );if(res == FR_OK){res = f_lseek(&fp,fp.fsize/2); //使用文件结构体的成员属性fsize获取文件大小,将文件指针定位到文件内容的中间//res = f_lseek(&fp,f_size(&fp)/2); //使用f_size()获取文件大小,将文件指针定位到文件内容的中间 printf("\r\n文件打开成功,准备读取数据!\r\n");res = f_read(&fp,&readBuffer,sizeof(readBuffer),&fnum);if(res==FR_OK){printf("》文件读取成功,读到字节数据:%d\r\n",fnum);printf("》读取得的文件数据为:\r\n%s \r\n", readBuffer); }else{printf("!!文件读取失败:(%d)\n",res);} f_close(&fp); }else{printf("\r\n文件打开失败,失败代码 = %d\r\n",res);}
3、创建目录及重命名
printf("\r\n--------------------目录创建和重命名--------------------\r\n");
res = f_opendir(&dir,"3:Hello");
if(res != FR_OK)
{printf("\r\n不存在该目录,将创建新的Hello文件夹\r\n");res = f_mkdir("3:Hello"); //如果目录不存在,则创建目录
}
else
{printf("\r\n存在该目录,关闭目录并删除!\r\n");res = f_closedir(&dir);f_unlink("3:Hello/testdir.txt");
}
if(res == FR_OK)
{printf("\r\n将FatFs文件系统测试例程.txt复制到Hello下,并重命名为testdir.txt\r\n");res = f_rename("3:FatFs文件系统测试例程.txt","3:Hello/testdir.txt");
}
readFile(&fp,"3:Hello/testdir.txt");
4、文件/文件夹信息获取
static FRESULT file_check(const TCHAR *path)
{FILINFO fInfo;/* 获取文件信息 */res = f_stat(path,&fInfo);if(res == FR_OK){printf("“%s”文件信息:\n",path);printf("》文件大小:%ld(字节)\n",fInfo.fsize);printf("》时间戳:%u/%02u/%02u,%02u:%02u\n",(fInfo.fdate >> 9)+1980,fInfo.fdate >> 5&15,fInfo.fdate & 31,fInfo.ftime>>11,fInfo.ftime >>5 &63);printf("》属性:%c%c%c%c%c\n\n",(fInfo.fattrib & AM_DIR)?'D':'-', //目录(fInfo.fattrib & AM_RDO)?'R':'-', //只读文件(fInfo.fattrib & AM_HID)?'H':'-', //隐藏文件(fInfo.fattrib & AM_SYS)?'S':'-', //系统文件(fInfo.fattrib & AM_ARC)?'A':'-'); //档案文件}elsec{printf("\r\n文件打开失败,失败代码 = %d\r\n",res);}return res;
}
在main
中调用:
res = file_check("3:Hello/testdir.txt");
在这里关于时间戳说明一下,因为之前get_fattime
函数我们用了一个空函数来骗过编译器,所以这里读出来的时间实际上是有问题的,等到后面有时间系统了,这个就可以实现了。
5、文件遍历
static FRESULT Scan_files(char *path)
{FRESULT res;FILINFO fInfo;DIR dir;int i;char *fn;
#if _USE_LFN //如果使用长文件名static char lfn[_MAX_LFN*2+1];fInfo.lfname = lfn;fInfo.lfsize = sizeof(lfn);
#endifres = f_opendir(&dir,path); //打开目录if(res == FR_OK){i = strlen(path);for(;;){res = f_readdir(&dir,&fInfo); //读取目录下的内容,再读会自动读到下一个文件if(res != FR_OK||fInfo.fname[0] == 0)break;
#if _USE_LFN/*这里其实不用看的,我们之前已经启用长文件名了,但是需要注意的是,虽然启用了长文件名,当存储文件名不够13个字节时,文件系统仍然会将文件名存储到fname中,只有文件名超过13时,才会存储到lfname中*/fn = *fInfo.lfname ? fInfo.lfname:fInfo.fname;
#elsefn = fInfo.name;
#endifif(*fn == '.') //如果遇到点,则表示当前目录,跳过即可continue;if(fInfo.fattrib & AM_DIR) //遇到目录时,递归调用{sprintf(&path[i],"/%s",fn); //将获取到的文件名合成为完整文件名(即包含卷标和目录名的)res = Scan_files(path); //递归遍历path[i] = 0;if(res != FR_OK) //如果打开失败,跳出循环break;}else{printf("%s/%s\r\n",path,fn);}}}return res;
}
OK,关于FatFs文件系统的内容就学习到这里,其实里面还有很多内容这里没有提到,有兴趣的可以去官网学习一下。
相关文章:

021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结
021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结 上节内容中,初步实现了FatFs文件系统的移植,并且实现了设备的挂载、文件打开/关闭与读写功能,这里对上节遗留的一些问题进行总结,并且继续完善文件…...

jQuery如何获取动态添加的元素
jQuery如何获取动态添加的元素 使用 on()方法 本质上使用了事件委派,将事件委派在父元素身上 自 jQuery 版本 1.7 起,on() 方法是 bind()、live() 和 delegate() 方法的新的替代品,但是由于on()方法必须有事件,没有事件时可选择de…...

Keepalived 在CentOS 7安装并配置监听MySQL双主
keepalived安装 MySQL双主配置请看这里:https://tongyao.blog.csdn.net/article/details/132016200?spm1001.2014.3001.5502 128、129两台服务器安装步骤相同,配置文件不同,下面有介绍。 1.安装相关依赖包,并下载keepalived安…...

深度学习,神经网络介绍
目录 1.神经网络的整体构架 2.神经网络架构细节 3.正则化与激活函数 4.神经网络过拟合解决方法 1.神经网络的整体构架 ConvNetJS demo: Classify toy 2D data 我们可以看看这个神经网络的网站,可以用来学习。 神经网络的整体构架如下1: 感知器&…...

中国AI大模型峰会“封神之作”!开发者不容错过这场夏季盛会
年度最强大模型顶会来袭!喊话中国数百万AI开发者,速来! 硬核来袭!中国AI大模型峰会“封神之作”,开发者们不容错过! 前瞻大模型发展趋势,紧跟这场大会! 中国科技超级碗,大模型最新前…...

Android Studio多渠道打包
使用环境: Android studio 多渠道打包 使用方法: 1 APP下build.gradle文件 flavorDimensions "default"productFlavors {huawei {dimension "default"manifestPlaceholders [ channel:"huawei" ]}xiaomi {dimension &…...

RK3566 Android11默认客户Launcher修改
前言 客户需要默认自己的Launcher为home,同时保留系统的Launcher3. 解决办法:在启动home应用之前设置一下默认Launcher。查找home app启动相关资料,找到了frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java的startHomeOnTaskDisplayA…...

ORB算法在opencv中实现方法
在OPenCV中实现ORB算法,使用的是: 1.实例化ORB orb cv.xfeatures2d.orb_create(nfeatures)参数: nfeatures: 特征点的最大数量 2.利用orb.detectAndCompute()检测关键点并计算 kp,des orb.detectAndCompute(gray,None)参数:…...

vue项目回显文本无法识别换行符
解决方法 1:使用<br/>替换文本中的\n,使用v-html渲染 <template> <div v-html"str"></div> </template> <script> let str 以下内容自动换行\n换行了 // 使用replace截取提换 this.str str.replace(/…...

Minio 部署
minio 官网:https://www.minio.org.cn/ 部署文档:https://www.minio.org.cn/docs/minio/container/operations/install-deploy-manage/deploy-minio-single-node-single-drive.html# 选择自己的部署环境: 我用的docker: docker pull qua…...

Kafka系列之:记录一次Kafka Topic分区扩容,但是下游flink消费者没有自动消费新的分区的解决方法
Kafka系列之:记录一次Kafka Topic分区扩容,但是下游flink消费者没有自动消费新的分区的解决方法 一、背景二、解决方法三、实现自动发现新的分区一、背景 生产环境Kafka集群压力大,Topic读写压力大,消费的lag比较大,因此通过扩容Topic的分区,增大Topic的读写性能理论上下…...

Ansible部署MariaDB galera集群(多主)
文章目录 Ansible部署MariaDB galera集群(多主)介绍节点规划基础环境准备编写剧本文件执行剧本文件查看集群状态测试 Ansible部署MariaDB galera集群(多主) 介绍 MariaDB Galera集群是一套基于同步复制的、多主的MySQL集群解决方案,使用节点没有单点故障ÿ…...

立体库-库龄
split 用法第一种: 1.对单个字符进行分割(注意这里是字符,不是字符串,故只能用单引号‘’) string sabcdeabcdeabcde; string[] sArrays.Split(c) ; foreach(string i in sArray) Console.WriteLine(i.ToString());…...

extern/头文件包含,实现一个函数被两个文件共用
目录 一、extern 1、在a.c文件中定义int add函数 2、在b.c文件中使用extern关键字声明add函数 二、用头文件包含的形式 1、在a.c文件中定义int add函数 2、创建一个名为a.h的头文件,其中包含add函数的函数原型 3、在b.c文件中包含a.c的头文件,并调…...

pgsql 查看某个表建立了那些索引sql
执行以下sql: SELECTns.nspname as schema_name,tab.relname as table_name,cls.relname as index_name,am.amname as index_type,idx.indisprimary as is_primary,idx.indisunique as is_unique FROMpg_index idx INNER JOIN pg_class cls ON cls.oididx.indexrel…...

【SCSS】网格布局中的动画
效果 index.html <!DOCTYPE html> <html><head><title> Document </title><link type"text/css" rel"styleSheet" href"index.css" /></head><body><div class"container">&l…...

Docker基础命令(一)
Docker使用1 一、运行终端 打开终端,输入docker images ,如果运行正常,表示docker已经可以在本电脑上使用了 二、docker常用命令 指令说明docker images查看已下载的镜像docker rmi 镜像名称:标签名删除已下载的镜像docker search 镜像从官…...

django4.2 day1Django快速入门
1、创建虚拟环境 打开cmd安装virtualenv pip install virtualenvwrapper-winworkon 查看虚拟环境mkvirtualenv 创建新的虚拟环境删除虚拟环境 rmvirtualenv 进入虚拟环境 workon env 2、创建django虚拟环境并安装django 创建虚拟环境mkvirtualenv django4env进入虚拟环境安…...

linux的exec和system函数介绍及选择
在应用程序中有时候需要调用第三方的应用,这是常见的需求。此时可以使用linux下的exec命令或system命令达到目的。但是这两个该选择哪个呢?有什么区别?下面总结介绍下。 exec和system介绍 在Linux中,exec命令用于在当前进程中执行…...

150行代码写一个Qt井字棋游戏
照例先演示一下: QT井字棋游戏,可以悔棋。 会在鼠标箭头处跟随一个下棋方的小棋子图标。 棋盘和棋子是自己画的,可以自行在对应的代码处更换自己喜欢的图片,不过要注意尺寸兼容。 以棋会友: 井字棋最关键的就是下棋了…...

k8s概念-controller
Controller作用和分类 controller用于控制pod 参考: 工作负载资源 | Kubernetes 控制器主要分为: Deployments 部署无状态应用,控制pod升级,回退 ReplicaSet 副本集,控制pod扩容,裁减 ReplicationController(相当于ReplicaSet的老版本,现在建议使用Deployments…...

Gis入门,根据起止点和一个控制点计算二阶贝塞尔曲线(共三个控制点组成的线段转曲线)
前言 本章讲解如何在gis地图中使用起止点和一个控制点(总共三个控制点)生成二阶贝塞尔曲线。 三阶贝塞尔曲线请参考下一章《Gis入门,使用起止点和两个控制点生成三阶贝塞尔曲线(共四个控制点)》 贝塞尔曲线(Bezier curve)介绍 贝塞尔曲线(Bezier curve)是一种数学…...

第1集丨Vue 江湖 —— Hello Vue
目录 一、简介1.1 参考网址1.2 下载 二、Hello Vue2.1 创建页面2.2 安装Live Server插件2.4 安装 vue-devtools2.5 预览效果 一、简介 Vue(读音 /vjuː/, 类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设…...

PCB制版技术
1、在头脑里形成一个原理图----现在就下载AD9盖版,诞生了一个问题,电路板去哪里买,买了怎么焊接电路和芯片,怎样流程化批量制作电子产品 1.1 形成一个PCB板,形成一个结构 1.2 焊接,嫁接,组装等 …...

大数据课程E7——Flume的Interceptor
文章作者邮箱:yugongshiyesina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Interceptor的概念和配置参数; ⚪ 掌握Interceptor的使用方法; ⚪ 掌握Interceptor的Host Interceptor; ⚪ 掌握Interceptor的…...

P2P网络NAT穿透原理(打洞方案)
1.关于NAT NAT技术(Network Address Translation,网络地址转换)是一种把内部网络(简称为内网)私有IP地址转换为外部网络(简称为外网)公共IP地址的技术,它使得一定范围内的多台主机只…...

Gof23设计模式之桥接外观模式
1.概述 又名门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度࿰…...

微服务性能分析工具 Pyroscope 初体验
Go 自带接口性能分析工具 pprof,较为常用的有以下 4 种分析: CPU Profiling: CPU 分析,按照一定的频率采集所监听的应用程序 CPU(含寄存器)的使用情况,可确定应用程序在主动消耗 CPU 周期时花费时间的位置…...

工作记录------单元测试(持续更新)
工作记录------单元测试 之前的工作中从来没有写过单元测试,新入职公司要求写单元测试, 个人觉得,作为程序员单元测试还是必须会写的 于此记录一下首次编写单元测试的过程。 首先引入单元测试相关的依赖 <dependency><groupId>…...

C#再windowForm窗体中绘画扇形并给其填充颜色
C#再windowForm窗体中绘画扇形并给其填充颜色 Graphics graphics this.CreateGraphics();graphics.SmoothingMode SmoothingMode.AntiAlias;int width this.Width;int height this.Height;h this.Height;w this.Width;Rectangle rct new Rectangle(0 - h / 6, 0 - h / 6…...