ESP32 Arduino 框架中 Preferences 类的使用指导:函数讲解与实战示例

📅 2026/8/11 17:24:25
ESP32 Arduino 框架中 Preferences 类的使用指导:函数讲解与实战示例
1. 引言为什么需要 Preferences在 ESP32 开发中我们经常需要存储一些配置参数、设备状态或用户数据这些数据需要在设备断电重启后依然能够保留。虽然可以使用文件系统如 SPIFFS、LittleFS或 EEPROM 模拟库但 ESP32 Arduino 核心库内置的Preferences类提供了一种更简单、高效且可靠的非易失性存储NVS解决方案。Preferences 库封装了 ESP32 的非易失性存储NVS功能具有以下优势键值对存储使用简单的键字符串来存取数据无需管理复杂的文件路径。数据类型丰富支持整型、浮点型、字符串、二进制数据等多种类型。命名空间隔离不同功能模块的数据可以存放在不同的命名空间下避免键名冲突。原子操作与磨损均衡底层 NVS 机制保证了数据写入的原子性并具有磨损均衡特性延长 Flash 寿命。使用简便无需手动初始化文件系统API 直观易用。2. 基本使用流程与头文件使用 Preferences 前需要包含相应的头文件并创建对象。#include Preferences.h Preferences preferences;基本操作遵循“打开 - 读写 - 关闭”的流程关闭操作会将数据真正提交到 Flash。3. 核心函数详解3.1 初始化与命名空间管理begin(const char* name, bool readOnlyfalse, const char* partition_labelNULL)功能打开一个命名空间。如果命名空间不存在则创建它。参数name命名空间名称用于数据隔离。readOnly是否为只读模式打开。默认为false读写模式。partition_label指定使用的 NVS 分区标签通常为NULL使用默认的 “nvs” 分区。返回值成功打开返回true失败返回false。end()功能关闭当前命名空间确保所有更改写入 Flash。这是一个重要的步骤不应省略。3.2 数据写入函数Put用于存储数据。函数名通常以put开头。putChar(const char* key, int8_t value)存储 8 位有符号整数。putUChar(const char* key, uint8_t value)存储 8 位无符号整数。putShort(const char* key, int16_t value)存储 16 位有符号整数。putUShort(const char* key, uint16_t value)存储 16 位无符号整数。putInt(const char* key, int32_t value)存储 32 位有符号整数。putUInt(const char* key, uint32_t value)存储 32 位无符号整数。putLong(const char* key, int32_t value)存储 32 位长整型与putInt相同。putULong(const char* key, uint32_t value)存储 32 位无符号长整型与putUInt相同。putLong64(const char* key, int64_t value)存储 64 位有符号整数。putULong64(const char* key, uint64_t value)存储 64 位无符号整数。putFloat(const char* key, float_t value)存储单精度浮点数。putDouble(const char* key, double_t value)存储双精度浮点数。putBool(const char* key, bool value)存储布尔值。putString(const char* key, const String value)存储字符串String 对象。putString(const char* key, const char* value)存储字符串C 风格字符串。putBytes(const char* key, const void* value, size_t len)存储任意二进制数据。3.3 数据读取函数Get用于读取数据。如果键不存在则返回指定的默认值。getChar(const char* key, int8_t defaultValue0)getUChar(const char* key, uint8_t defaultValue0)getShort(const char* key, int16_t defaultValue0)getUShort(const char* key, uint16_t defaultValue0)getInt(const char* key, int32_t defaultValue0)getUInt(const char* key, uint32_t defaultValue0)getLong(const char* key, int32_t defaultValue0)getULong(const char* key, uint32_t defaultValue0)getLong64(const char* key, int64_t defaultValue0)getULong64(const char* key, uint64_t defaultValue0)getFloat(const char* key, float_t defaultValueNAN)getDouble(const char* key, double_t defaultValueNAN)getBool(const char* key, bool defaultValuefalse)String getString(const char* key, const String defaultValueString())size_t getBytes(const char* key, void* buf, size_t maxLen)读取二进制数据到缓冲区返回实际读取的字节数。3.4 其他实用函数remove(const char* key)删除指定键及其值。clear()清除当前命名空间下的所有键值对。freeEntries()获取当前命名空间下剩余的可用条目数键值对数量。isKey(const char* key)检查指定键是否存在。4. 综合使用示例下面是一个完整的示例演示如何存储 WiFi 配置、设备启动次数和一段自定义二进制数据。#include Preferences.h Preferences prefs; void setup() { Serial.begin(115200); delay(1000); // 1. 打开或创建名为 my_app 的命名空间 if (!prefs.begin(my_app)) { Serial.println(Failed to open preferences namespace); return; } // 2. 读写数据 // 读取启动次数如果不存在则默认为0然后加1并写回 uint32_t bootCount prefs.getUInt(boot_count, 0); bootCount; prefs.putUInt(boot_count, bootCount); Serial.printf(Device boot count: %u\n, bootCount); // 存储 WiFi SSID 和密码 prefs.putString(wifi_ssid, MyHomeWiFi); prefs.putString(wifi_pass, SecurePassword123); // 读取 WiFi 配置如果之前存储过 String ssid prefs.getString(wifi_ssid, ); String pass prefs.getString(wifi_pass, ); if (ssid.length() 0) { Serial.printf(Stored WiFi SSID: %s\n, ssid.c_str()); // 注意实际项目中不应在日志中打印密码 } // 存储和读取浮点数例如传感器校准值 float calibrationFactor 1.025; prefs.putFloat(cal_factor, calibrationFactor); float readCal prefs.getFloat(cal_factor, 1.0); Serial.printf(Calibration factor: %.3f\n, readCal); // 存储和读取二进制数据例如一个简单的结构体 struct MyData { uint8_t id; uint16_t value; } dataToStore {0xAB, 1234}; prefs.putBytes(my_struct, dataToStore, sizeof(dataToStore)); MyData dataRead; size_t len prefs.getBytes(my_struct, dataRead, sizeof(dataRead)); if (len sizeof(MyData)) { Serial.printf(Read binary data: ID0x%02X, Value%u\n, dataRead.id, dataRead.value); } // 3. 关闭命名空间提交更改 prefs.end(); Serial.println(Preferences saved successfully.); } void loop() { // 主循环无需操作 Preferences delay(10000); }5. 高级技巧与注意事项5.1 命名空间规划为不同的功能模块使用不同的命名空间例如wifi_config、device_settings、user_data。这可以提高代码的可维护性并允许单独清除某个模块的数据。5.2 错误处理始终检查begin()的返回值。写入失败可能由于 NVS 分区已满或 Flash 损坏。5.3 数据更新策略频繁更新同一个键可能会加速 Flash 磨损。对于频繁变化的数据如传感器实时值应考虑在 RAM 中缓存定期或仅在必要时写入 Preferences。5.4 字符串长度限制单个键值对的总大小键名长度 数据长度存在限制通常约为 1984 字节。过长的字符串应分段存储或考虑使用文件系统。5.5 与文件系统的选择使用 Preferences 当存储键值对形式的配置、状态标志、计数器等小型结构化数据。使用 SPIFFS/LittleFS 当需要存储大文件、日志、网页资源或非结构化的长文本。6. 常见问题排查FAQQ数据写入后重启读取不到A确保每次修改后都调用了end()或close()Preferences类中end()即关闭。Qbegin()失败返回 falseA检查 NVS 分区是否在分区表中被正确配置或 Flash 存储空间是否已满。Q可以存储数组吗A可以使用putBytes和getBytes来存储和读取整个数组。Q如何清空所有数据A在 Arduino IDE 的“工具”菜单中选择“擦除 Flash”选项。在代码中可以对特定命名空间使用clear()。7. 总结Preferences 库是 ESP32 Arduino 开发中管理非易失性数据的利器。它通过简单的键值对 API 和内置的磨损均衡机制让数据持久化变得安全便捷。掌握其核心函数和最佳实践可以有效地存储设备配置、运行状态和用户设置提升项目的可靠性。建议在实际项目中结合具体需求规划命名空间和键名并养成良好的“打开-关闭”习惯确保数据完整性。