当前位置: 首页 > backend >正文

SOC-ESP32S3部分:23-文件系统

飞书文档https://x509p6c8to.feishu.cn/wiki/SXf5w6seIijVVskvic5cNT2wng4

目前,ESP-IDF 框架支持三种文件系统。

SPIFFS(SPI Flash File System)

  • 简介:SPIFFS 是专门为 SPI NOR Flash 设备设计的轻量级文件系统,适用于资源受限的嵌入式系统,在 ESP32 开发中较为常用。
  • 特点
  • 轻量级:占用资源少,对内存和处理能力的要求较低,适合在资源有限的 ESP32 设备上运行。
  • 磨损均衡:支持基本的磨损均衡功能,能够均匀地将数据写入 Flash 芯片的各个块,延长 Flash 的使用寿命。
  • 简单易用:API 相对简单,易于集成到项目中,开发人员可以方便地进行文件的读写操作。
  • 不支持大文件:由于其设计初衷是用于存储小文件,对于大文件的处理能力有限,且文件系统的最大容量也受到一定限制。
  • 适用场景:适合存储配置文件、小图片、脚本等小文件,例如存储设备的配置信息、简单的网页文件等。

FATFS

  • 简介:FATFS 是一个通用的 FAT 文件系统模块,遵循 ANSI C 标准,与平台无关。ESP-IDF 可以通过移植 FATFS 来支持 FAT12、FAT16 和 FAT32 文件系统。
  • 特点
  • 兼容性好:FAT 文件系统是一种广泛使用的文件系统格式,在各种操作系统(如 Windows、Linux 等)中都能很好地支持,方便与其他设备进行数据交互。
  • 支持大文件:能够处理较大的文件和文件夹,适用于需要存储大文件的场景。
  • 功能丰富:支持文件的创建、删除、读写、重命名等常见操作,还支持文件权限和目录结构。
  • 资源占用较多:相比于 SPIFFS,FATFS 需要更多的内存和处理能力来运行,对系统资源有一定的要求。
  • 适用场景:适合需要与其他设备共享数据、存储大文件的场景,例如存储多媒体文件(如音频、视频)、大型配置文件等。

LittleFS

  • 简介:LittleFS 是一种专为嵌入式系统设计的日志结构文件系统,旨在提供高性能、可靠性和低资源占用。
  • 特点
  • 高性能:采用日志结构设计,具有较高的写入性能和随机访问性能,能够快速地进行文件的读写操作。
  • 可靠性强:支持数据的原子写入和崩溃恢复功能,在系统异常断电或崩溃的情况下,能够保证数据的完整性和一致性。
  • 磨损均衡:提供了更高级的磨损均衡算法,能够更有效地延长 Flash 芯片的使用寿命。
  • 资源占用适中:相比于 FATFS,LittleFS 的资源占用相对较少,但比 SPIFFS 略高。
  • 适用场景:适合对文件系统性能和可靠性要求较高的场景,例如存储实时数据、重要的配置文件等。

课程主要讲解SPIFFS,其它文件系统的使用都是类似的,很容易扩展。

SPIFFS 是一个用于 SPI NOR flash 设备的嵌入式文件系统,支持磨损均衡、文件系统一致性检查等功能。

SPIFFS NVS 的区别

SPIFFS(Serial Peripheral Interface Flash File System)和 NVS(Non-Volatile Storage)都是 ESP32-S3 的存储系统,但它们有一些关键的区别。

NVS 在 SPI NOR flash 上实现了一个有容错性,和磨损均衡功能的键值对存储。

NVS 可以存储一些 PHY 初始化数据,也可以存储其他数据,一些断电存储的数据建议放在这里。

总的来说,SPIFFS 更适合用于存储文件,而 NVS 更适合用于存储键值对数据。具体使用哪种存储系统,取决于应用需求。

1.1、创建分区表

同理,因为文件系统需要用到Flash存储,所以也得进行分区表的创建

# Name,   Type, SubType, Offset,  Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs,      data, nvs,     ,        0x6000,
phy_init, data, phy,     ,        0x1000,
factory,  app,  factory, ,        1M,
storage,  data, spiffs,  ,        0xF0000,

然后通过idf.py menuconfig配置自定义分区表

2.1、注册&格式化文件系统

有了分区后,就可以进行文件系统的注册函数esp_vfs_spiffs_register

esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t *conf);
参数
const esp_vfs_spiffs_conf_t *conf:
指向 esp_vfs_spiffs_conf_t 结构体的指针,包含 SPIFFS 文件系统的配置信息。返回值
esp_err_t
表示函数执行的结果,通常为以下几种情况:
ESP_OK: 成功初始化并挂载 SPIFFS 文件系统。
ESP_FAIL: 挂载或格式化失败。
ESP_ERR_NOT_FOUND: 未找到 SPIFFS 分区。
ESP_ERR_NO_MEM: 内存不足,无法初始化文件系统。
ESP_ERR_INVALID_ARG: 输入参数无效。
其他可能的错误代码,具体取决于底层实现。

esp_vfs_spiffs_conf_t 结构体用于配置 SPIFFS(SPI Flash File System)文件系统的参数。通过设置这些参数,可以控制 SPIFFS 文件系统的挂载行为、分区选择、最大同时打开的文件数以及挂载失败时的处理方式。

字段说明
base_path: 文件系统的挂载路径前缀。所有通过该文件系统访问的文件路径都将基于此路径。。
例如,如果 base_path 设置为 "/spiffs",则文件 hello.txt 的完整路径将是 "/spiffs/hello.txt"。partition_label: 可选参数,指定要使用的 SPIFFS 分区的标签,如果有多个 SPIFFS 分区,可以通过设置 partition_label 来指定具体的分区。
如果不设置,则默认使用第一个子类型为 spiffs 的分区。max_files: 最大同时打开的文件数。format_if_mount_failed: 如果为 true,则在挂载失败时自动格式化文件系统。
说明: 如果挂载 SPIFFS 分区失败(例如分区损坏或未初始化),
设置此标志为 true 可以自动格式化分区,使其重新可用。

使用参考:

    // 配置 SPIFFS 文件系统esp_vfs_spiffs_conf_t conf = {.base_path = "/spiffs",            // 文件系统的挂载路径.partition_label = NULL,           // 使用默认的 SPIFFS 分区标签.max_files = 5,                    // 最大同时打开的文件数.format_if_mount_failed = true     // 如果挂载失败,则格式化文件系统};// 使用上述配置初始化并挂载 SPIFFS 文件系统esp_err_t ret = esp_vfs_spiffs_register(&conf);// 处理挂载结果if (ret != ESP_OK) {if (ret == ESP_FAIL) {ESP_LOGE(TAG, "Failed to mount or format filesystem"); // 挂载或格式化失败} else if (ret == ESP_ERR_NOT_FOUND) {ESP_LOGE(TAG, "Failed to find SPIFFS partition"); // 未找到 SPIFFS 分区} else {ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); // 初始化 SPIFFS 失败}return;}

3.1、获取文件系统的信息

注册完成后,就可以使用esp_spiffs_info 函数用于获取指定 SPIFFS 分区的总大小和已使用的空间大小。

esp_err_t esp_spiffs_info(const char* partition_label, size_t* total, size_t* used);
参数
const char* partition_label:
SPIFFS 分区的标签。如果设置为 NULL,则使用默认的 SPIFFS 分区。size_t* total:
用于存储 SPIFFS 分区的总大小(以字节为单位)。size_t* used:
用于存储 SPIFFS 分区已使用的空间大小(以字节为单位)。

使用参考:

    // 获取 SPIFFS 分区的信息size_t total = 0, used = 0;ret = esp_spiffs_info(conf.partition_label, &total, &used);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));// 获取分区信息失败,格式化esp_spiffs_format(conf.partition_label);return;} else {ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); // 分区大小信息}

4.1、检查文件系统的完整性

最后,调用esp_spiffs_check 函数用于检查 SPIFFS 文件系统的完整性。具体来说:

  • 它会扫描指定的 SPIFFS 分区,查找并修复文件系统中的潜在问题。
  • 这个函数可以帮助检测和修复由于突然断电、程序异常终止等原因导致的文件系统损坏。
  • 检查过程包括验证文件系统结构、索引节点、数据块等的正确性。
使用参考// 检查报告的分区大小信息的一致性if (used > total) {ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check()."); // 已使用字节数不能大于总字节数,执行 SPIFFS_check//如果 ESP32-S3 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。ret = esp_spiffs_check(conf.partition_label);if (ret != ESP_OK) {ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret)); // SPIFFS_check 失败return;} else {ESP_LOGI(TAG, "SPIFFS_check() successful"); // SPIFFS_check 成功}}

5.1、创建文件、读写操作

如果到这里都没问题,我们就可以用c的文件操作函数进行文件的创建、写入、读取等操作了,最终代码如下:

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"static const char *TAG = "example";void app_main(void)
{// 初始化 SPIFFSESP_LOGI(TAG, "Initializing SPIFFS");// 配置 SPIFFS 文件系统esp_vfs_spiffs_conf_t conf = {.base_path = "/spiffs",            // 文件系统的挂载路径.partition_label = NULL,           // 使用默认的 SPIFFS 分区标签.max_files = 5,                    // 最大同时打开的文件数.format_if_mount_failed = true     // 如果挂载失败,则格式化文件系统};// 使用上述配置初始化并挂载 SPIFFS 文件系统esp_err_t ret = esp_vfs_spiffs_register(&conf);// 处理挂载结果if (ret != ESP_OK) {if (ret == ESP_FAIL) {ESP_LOGE(TAG, "Failed to mount or format filesystem"); // 挂载或格式化失败} else if (ret == ESP_ERR_NOT_FOUND) {ESP_LOGE(TAG, "Failed to find SPIFFS partition"); // 未找到 SPIFFS 分区} else {ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); // 初始化 SPIFFS 失败}return;}// 获取 SPIFFS 分区的信息size_t total = 0, used = 0;ret = esp_spiffs_info(conf.partition_label, &total, &used);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));// 获取分区信息失败,格式化esp_spiffs_format(conf.partition_label);return;} else {ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); // 分区大小信息}// 检查报告的分区大小信息的一致性if (used > total) {ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check()."); // 已使用字节数不能大于总字节数,执行 SPIFFS_check//如果 ESP32-S3 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。ret = esp_spiffs_check(conf.partition_label);if (ret != ESP_OK) {ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret)); // SPIFFS_check 失败return;} else {ESP_LOGI(TAG, "SPIFFS_check() successful"); // SPIFFS_check 成功}}// 使用 POSIX 和 C 标准库函数来处理文件// 首先创建一个文件ESP_LOGI(TAG, "Opening file"); // 打开文件FILE* f = fopen("/spiffs/hello.txt", "w");if (f == NULL) {ESP_LOGE(TAG, "Failed to open file for writing"); // 打开文件失败return;}fprintf(f, "Hello World!\n"); // 写入文件fclose(f);ESP_LOGI(TAG, "File written"); // 文件写入成功// 打开文件进行读取ESP_LOGI(TAG, "Reading file"); // 读取文件f = fopen("/spiffs/hello.txt", "r");if (f == NULL) {ESP_LOGE(TAG, "Failed to open file for reading"); // 打开文件失败return;}char line[64];fgets(line, sizeof(line), f); // 读取文件内容fclose(f);// 去掉换行符char* pos = strchr(line, '\n');if (pos) {*pos = '\0';}ESP_LOGI(TAG, "Read from file: '%s'", line); // 读取到的内容// 完成所有操作,卸载分区并禁用 SPIFFSesp_vfs_spiffs_unregister(conf.partition_label);ESP_LOGI(TAG, "SPIFFS unmounted"); // SPIFFS 卸载成功
}

首次启动时,因为需要初始化挂载格式化文件系统,所以会阻塞10s左右,这是正常的

扩展:如何把本地文件烧录到板卡文件系统中?

spiffs_create_partition_image 是一个用于将文件系统中的文件打包成 SPIFFS 镜像并烧录到 ESP32 Flash中的命令,可以在程序烧录阶段一同将自定义的SPIFFS 文件镜像烧录到开发板。

使用方法很简单,例如,我在电脑创建一个txt文件夹,文件夹内部创建一个文件hello1.txt

demo/txt/hello1.txt

this is hello1 txt

然后在demo/main/CMakeLists.txt中,就可以添加spiffs_create_partition_image指令

指令参数如下

spiffs_create_partition_image(分区名 "path/to/files" FLASH_IN_PROJECT)

所以内容如下:

spiffs_create_partition_image(storage "../txt" FLASH_IN_PROJECT)

这句指令的意思是将工程下../txt 目录中的文件打包成 SPIFFS 镜像,并且。

最终用代码打开

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"static const char *TAG = "example";void app_main(void)
{// 初始化 SPIFFSESP_LOGI(TAG, "Initializing SPIFFS");// 配置 SPIFFS 文件系统esp_vfs_spiffs_conf_t conf = {.base_path = "/spiffs",            // 文件系统的挂载路径.partition_label = NULL,           // 使用默认的 SPIFFS 分区标签.max_files = 5,                    // 最大同时打开的文件数.format_if_mount_failed = true     // 如果挂载失败,则格式化文件系统};// 使用上述配置初始化并挂载 SPIFFS 文件系统esp_err_t ret = esp_vfs_spiffs_register(&conf);// 处理挂载结果if (ret != ESP_OK) {if (ret == ESP_FAIL) {ESP_LOGE(TAG, "Failed to mount or format filesystem"); // 挂载或格式化失败} else if (ret == ESP_ERR_NOT_FOUND) {ESP_LOGE(TAG, "Failed to find SPIFFS partition"); // 未找到 SPIFFS 分区} else {ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); // 初始化 SPIFFS 失败}return;}// 获取 SPIFFS 分区的信息size_t total = 0, used = 0;ret = esp_spiffs_info(conf.partition_label, &total, &used);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));// 获取分区信息失败,格式化esp_spiffs_format(conf.partition_label);return;} else {ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); // 分区大小信息}// 检查报告的分区大小信息的一致性if (used > total) {ESP_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check()."); // 已使用字节数不能大于总字节数,执行 SPIFFS_check//如果 ESP32-S3 在文件系统操作期间断电,可能会导致 SPIFFS 损坏。但是仍可通过 esp_spiffs_check 函数恢复文件系统。ret = esp_spiffs_check(conf.partition_label);if (ret != ESP_OK) {ESP_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret)); // SPIFFS_check 失败return;} else {ESP_LOGI(TAG, "SPIFFS_check() successful"); // SPIFFS_check 成功}}// 打开文件进行读取ESP_LOGI(TAG, "Reading file"); // 读取文件FILE* f = fopen("/spiffs/hello1.txt", "r");if (f == NULL) {ESP_LOGE(TAG, "Failed to open file for reading"); // 打开文件失败return;}char line[64];fgets(line, sizeof(line), f); // 读取文件内容fclose(f);// 去掉换行符char* pos = strchr(line, '\n');if (pos) {*pos = '\0';}ESP_LOGI(TAG, "Read from file: '%s'", line); // 读取到的内容// 完成所有操作,卸载分区并禁用 SPIFFSesp_vfs_spiffs_unregister(conf.partition_label);ESP_LOGI(TAG, "SPIFFS unmounted"); // SPIFFS 卸载成功
}
http://www.xdnf.cn/news/10479.html

相关文章:

  • 基于STM32的流水线机器人自动分拣系统设计与实现:技术、优化与应用
  • 力扣HOT100之动态规划:416. 分割等和子集
  • 复杂业务场景下 JSON 规范设计:Map<String,Object>快速开发 与 ResponseEntity精细化控制HTTP 的本质区别与应用场景解析
  • OS10.【Linux】yum命令
  • Tomcat 线程模型详解性能调优
  • 【从零开始学习QT】信号和槽
  • 性能优化 - 案例篇:缓冲区
  • 【PyQt5】PyQt5初探 - 一个简单的例程
  • Python 训练营打卡 Day 32-官方文档的阅读
  • Client-Side Path Traversal 漏洞学习笔记
  • HackMyVM-Teacher
  • 逆向入门(1)
  • 【irregular swap】An Examination of Fairness of AI Models for Deepfake Detection
  • pikachu通关教程-CSRF
  • CppCon 2014 学习:C++ Memory Model Meets High-Update-Rate Data Structures
  • 第1章 数据分析简介
  • 工作流引擎-10-什么是 BPM?
  • 恶意软件清理工具,让Mac电脑安全更简单
  • Marvin - 生成结构化输出 和 构建AI工作流
  • 深度优先搜索(DFS)邻接矩阵实现
  • 计算机网络 TCP篇常见面试题总结
  • ps填充图层
  • Adobe LiveCycle ES、LiveCycle DS 与 BlazeDS 关系解析与比较
  • c++ QicsTable使用实例
  • linux信号详解
  • 人工智能100问☞第38问:什么是多模态模型?
  • 【课堂笔记】生成对抗网络 Generative Adversarial Network(GAN)
  • 任务23:创建天气信息大屏Django项目
  • 【BootLoader】之stm32F407实现bootloader相关问题
  • Python+MongoDb使用手册(精简)