You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ESP32的SPIFFS中用ArduinoJson6存储多个SSID与密码

问题描述

目标是在ESP32的SPIFFS中使用ArduinoJson6存储多组SSID和密码,此前尝试直接追加文件或读取文档、删除文件后重新序列化保存的方式,均无法得到预期的JSON结构。

预期JSON结构

{"information":[
    { "SSID":"variable blaat1", "PASS":"variable Abc1", "NUMBER": "1" },
    { "SSID":"variable blaat2", "PASS":"variable Abc2", "NUMBER": "2" },
    { "SSID":"variable blaat3", "PASS":"variable Abc3", "NUMBER": "3" },
    { "SSID":"variable blaat4", "PASS":"variable Abc4", "NUMBER": "4" },
    { "SSID":"variable blaat5", "PASS":"variable Abc5", "NUMBER": "5" }
]}

实际错误结构

多次操作后得到的无效结构:

{
  "information": {},
  "test": [
    "mooiman\n",
    "mooiweer\n"
  ],
  "number": [
    1,
    2
  ]
}

测试代码

#include <Arduino.h>
#include <WiFi.h>
#include "FS.h"
#include "SPIFFS.h"
#include <ArduinoJson.h>

int numberofInputs = 1;
String ssid = "YourSSID";
String passwords = "YourPassword";
String readString;
char FileReadBuff[1024];
DynamicJsonDocument doc(1024);

void readFile(fs::FS &fs, const char * path){
   if (SPIFFS.exists("/SSID.json") == false)
  {
   File file = SPIFFS.open("/SSID.json", FILE_WRITE);
 
   if (!file) {
    Serial.println("There was an error opening the file for writing");
    return;
  }
 
  if (file.print("SSID")) {
    Serial.println("File was written");
  } else {
    Serial.println("File write failed");
  }
  file.close();
 }
    Serial.printf("Reading file: %s\r\n", path);

    File file = fs.open(path);
    if(!file || file.isDirectory()){
        Serial.println("- failed to open file for reading");
        return;
    }
    uint16_t i = 0;
    Serial.println("reading");
    while (file.available()) {
    FileReadBuff[i] = file.read();
    i++;
  }
    file.close();
}
void CleanFile(fs::FS &fs, const char * path, const char * message) {
  for( int i = 0; i < sizeof(FileReadBuff);  ++i ){
  FileReadBuff[i] = (char)0;
  }
  File file = SPIFFS.open(path, FILE_WRITE);
  if (fs.remove(path)) {
    Serial.println("\r\n- file cleaned");
  } else {
    Serial.println("\r\n- Cleaning failed");
  }
  file.print(path);
  
}
void appendFile(fs::FS &fs, const char * path, const char * message){
   if (SPIFFS.exists("/SSID.json") == false)
  {
   File file = SPIFFS.open("/SSID.json", FILE_WRITE);
 
   if (!file) {
    Serial.println("There was an error opening the file for writing");
    return;
  }
 
  if (file.print("SSID")) {
    Serial.println("File was written");
  } else {
    Serial.println("File write failed");
  }
  file.close();
 }
    Serial.printf("Appending to file: %s\r\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("- failed to open file for appending");
        return;
    }
    if(file.println(message)){
        Serial.println("- message appended");
    } else {
        Serial.println("- append failed");
    }
    file.close();
}

void Deserialization(){
 

  for( int i = 0; i < sizeof(FileReadBuff);  ++i ){
  FileReadBuff[i] = (char)0;
  }

  readFile(SPIFFS, "/SSID.json");  //read everything from ssid.json file
  const char * JsonFF = FileReadBuff; // put everything in to const char
  Serial.print("Json From File:"); Serial.println(JsonFF);
  
  DeserializationError error = deserializeJson(doc, JsonFF);
  if(error){
     Serial.print(F("deserializeJson() failed: ")); Serial.println(error.f_str()); // if not legit print error
  }
  if(!error){
    String information = doc["information"];

     Serial.println(information);
     information = "";
  }
}

void testjson(){


  readString = "";

while(readString.length() < 1) {
  while (Serial.available()) {
    delay(10);  //small delay to allow input buffer to fill
    if (Serial.available() > 0) {
      char c = Serial.read();  //gets one byte from serial buffer
      if (c == ',') {
        break;
      }  //breaks out of capture loop to print readstring
      readString += c;
    } //makes the string readString
  }
  if (readString.length() > 0) {
    Serial.println(readString); //prints string to serial port out

    if (readString.indexOf("READ") >= 0) {
      Serial.println("reading file");
      readFile(SPIFFS, "/SSID.json");
      
      Serial.println(FileReadBuff);

      for( int i = 0; i < sizeof(FileReadBuff);  ++i ){
       FileReadBuff[i] = (char)0;
      }
      
    }
    if (readString.indexOf("DES") >= 0) {                      //DEZ deserialize will result in an error because json file is currently not valid 
      Serial.println("reading deserialized json");
      Deserialization();
      
    }
    if (readString.indexOf("CLEAN") >= 0) {                    //CLEAN cleans the SSID.json file
      Serial.println("reading deserialized json");
      CleanFile(SPIFFS, "/SSID.json", "");
    }
    
    if (readString.indexOf("WRANDOM") >= 0){                   //WRANDOM writes a random string to the SSID.json file
      readString = "";
      Serial.println("Going to write the following input:");   //waiting for user input
      while(readString.length() < 1) {
       while (Serial.available()) {
        delay(10);  //small delay to allow input buffer to fill
        if (Serial.available() > 0) {
        char c = Serial.read();  //gets one byte from serial buffer
        if (c == ',') {
        break;
        }  //breaks out of capture loop to print readstring
        readString += c;
    } //makes the string readString
  }
  if (readString.length() > 0) {
    Serial.println(readString); //prints string to serial port out
      CleanFile(SPIFFS, "/SSID.json", "");
      JsonObject information = doc.createNestedObject("information");

      String SerializedJson = "";

      doc["test"].add(readString);
      doc["number"].add(numberofInputs);
      
      serializeJsonPretty(doc, SerializedJson);
     
      appendFile(SPIFFS, "/SSID.json", SerializedJson.c_str());
      SerializedJson = "";
      numberofInputs ++;
      return;

     }
    }
   }
  }
 }
}


void setup() {
   Serial.begin(115200);
    if (!SPIFFS.begin(true)) {
      Serial.println("An Error has occurred while mounting SPIFFS");
   return;
  }
  
  if (SPIFFS.exists("/SSID.json") == false)
  {
   File file = SPIFFS.open("/SSID.json", FILE_WRITE);
 
   if (!file) {
    Serial.println("There was an error opening the file for writing");
    return;
  }
 
  if (file.print("SSID")) {
    Serial.println("File was written");
  } else {
    Serial.println("File write failed");
  }
  file.close();
 }
   WiFi.mode(WIFI_MODE_STA);

   WiFi.begin(ssid.c_str(), passwords.c_str());

   while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
    }

  Serial.println("Connected");
}

void loop() {
  readString = "";
  Serial.println("Ready for new input: ");
  testjson();
}

操作流程

发送WRANDOM指令后输入内容,多次执行该操作,再发送READ指令查看/SSID.json文件,发现结构不符合预期。

备注:DynamicJsonDocument初始为空;暂不考虑LittleFS,优先解决当前SPIFFS的问题,也可考虑为每组SSID+密码创建单独文件。


解决方案

原代码核心问题

  1. 初始文件非法:首次创建文件时写入的是"SSID"字符串,不是合法JSON,导致后续反序列化失败
  2. 结构逻辑错误:WRANDOM分支错误创建information嵌套对象而非数组,且使用了test/number等无关键名
  3. 更新逻辑错误:没有读取现有JSON并追加新条目,而是清空后写入错误结构
  4. CleanFile函数逻辑混乱:删除文件后又打开写入路径字符串,导致文件内容无效

修正步骤

  1. 初始化合法空JSON:首次创建文件时写入{"information":[]},确保后续反序列化正常
  2. 正确读取并更新JSON:每次新增条目时,先读取现有文件反序列化到doc,获取information数组,添加新的SSID/PASS对象
  3. 覆盖写入完整JSON:更新完成后,直接覆盖写入整个JSON结构,避免追加导致的格式错误
  4. 修正CleanFile函数:清空文件内容为合法空JSON,而非删除后写入无效内容

完整修正代码

#include <Arduino.h>
#include <WiFi.h>
#include "FS.h"
#include "SPIFFS.h"
#include <ArduinoJson.h>

int numberofInputs = 1;
String ssid = "YourSSID";
String passwords = "YourPassword";
String readString;
char FileReadBuff[1024];
DynamicJsonDocument doc(1024);

void readFile(fs::FS &fs, const char * path){
  // 初始化文件为合法空JSON
  if (!SPIFFS.exists(path))
  {
    File file = fs.open(path, FILE_WRITE);
    if (!file) {
      Serial.println("Failed to open file for writing");
      return;
    }
    if (file.print("{\"information\":[]}")) {
      Serial.println("Initial JSON file created");
    } else {
      Serial.println("File write failed");
    }
    file.close();
  }
  Serial.printf("Reading file: %s\r\n", path);

  File file = fs.open(path);
  if(!file || file.isDirectory()){
    Serial.println("- failed to open file for reading");
    return;
  }
  uint16_t i = 0;
  memset(FileReadBuff, 0, sizeof(FileReadBuff)); // 先清空缓冲区
  while (file.available() && i < sizeof(FileReadBuff)-1) { // 防止缓冲区溢出
    FileReadBuff[i] = file.read();
    i++;
  }
  file.close();
}

void CleanFile(fs::FS &fs, const char * path) {
  File file = fs.open(path, FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file for cleaning");
    return;
  }
  if(file.print("{\"information\":[]}")){
    Serial.println("File cleaned");
  } else {
    Serial.println("Clean failed");
  }
  file.close();
  memset(FileReadBuff, 0, sizeof(FileReadBuff));
  numberofInputs = 1; // 重置计数
}

void Deserialization(){
  memset(FileReadBuff, 0, sizeof(FileReadBuff));
  readFile(SPIFFS, "/SSID.json");
  const char * JsonFF = FileReadBuff;
  Serial.print("Json From File:"); Serial.println(JsonFF);
  
  DeserializationError error = deserializeJson(doc, JsonFF);
  if(error){
    Serial.print(F("deserializeJson() failed: ")); Serial.println(error.f_str());
    return;
  }
  
  JsonArray infoArray = doc["information"].as<JsonArray>();
  if(infoArray.isNull()){
    Serial.println("information array not found");
    return;
  }
  
  Serial.println("Deserialized entries:");
  for(JsonObject entry : infoArray){
    Serial.printf("NUMBER: %s, SSID: %s, PASS: %s\n", 
                  entry["NUMBER"].as<const char*>(),
                  entry["SSID"].as<const char*>(),
                  entry["PASS"].as<const char*>());
  }
}

void testjson(){
  readString = "";
  while(readString.length() < 1) {
    while (Serial.available()) {
      delay(10);
      if (Serial.available() > 0) {
        char c = Serial.read();
        if (c == '\n') { // 用换行结束指令输入
          break;
        }
        readString += c;
      }
    }
  }
  readString.trim(); // 去掉首尾空白字符
  if (readString.length() == 0) return;
  
  Serial.println("Received command: " + readString);

  if (readString.equals("READ")) {
    Serial.println("Reading file content:");
    readFile(SPIFFS, "/SSID.json");
    Serial.println(FileReadBuff);
    memset(FileReadBuff, 0, sizeof(FileReadBuff));
  }
  else if (readString.equals("DES")) {
    Serial.println("Deserializing JSON:");
    Deserialization();
  }
  else if (readString.equals("CLEAN")) {
    Serial.println("Cleaning file:");
    CleanFile(SPIFFS, "/SSID.json");
  }
  else if (readString.equals("WRANDOM")) {
    readString = "";
    Serial.println("Enter SSID,PASS (split by comma, press enter to confirm):");
    while(readString.length() < 1) {
      while (Serial.available()) {
        delay(10);
        if (Serial.available() > 0) {
          char c = Serial.read();
          if (c == '\n') {
            break;
          }
          readString += c;
        }
      }
    }
    readString.trim();
    if (readString.length() == 0) return;
    
    Serial.println("Input received: " + readString);
    int commaIndex = readString.indexOf(',');
    if(commaIndex == -1){
      Serial.println("Invalid format! Please use: SSID,PASS");
      return;
    }
    String inputSSID = readString.substring(0, commaIndex);
    String inputPASS = readString.substring(commaIndex+1);
    inputSSID.trim();
    inputPASS.trim();
    
    // 读取现有JSON
    doc.clear();
    readFile(SPIFFS, "/SSID.json");
    DeserializationError error = deserializeJson(doc, FileReadBuff);
    if(error){
      Serial.print("deserializeJson failed: ");
      Serial.println(error.f_str());
      return;
    }

    // 获取或创建information数组
    JsonArray infoArray = doc["information"].as<JsonArray>();
    if(infoArray.isNull()){
      infoArray = doc.createNestedArray("information");
    }

    // 添加新条目
    JsonObject newEntry = infoArray.createNestedObject();
    newEntry["SSID"] = inputSSID;
    newEntry["PASS"] = inputPASS;
    newEntry["NUMBER"] = String(numberofInputs);

    // 覆盖写入文件
    File file = SPIFFS.open("/SSID.json", FILE_WRITE);
    if(!file){
      Serial.println("Failed to open file for writing");
      return;
    }
    if(serializeJson(doc, file)){
      Serial.println("New entry added successfully");
    } else {
      Serial.println("Failed to write to file");
    }
    file.close();

    numberofInputs++;
    return;
  }
  else {
    Serial.println("Unknown command! Available commands: READ, DES, CLEAN, WRANDOM");
  }
}

void setup() {
  Serial.begin(115200);
  if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }
  
  // 初始化SSID.json文件
  if (!SPIFFS.exists("/SSID.json"))
  {
    File file = SPIFFS.open("/SSID.json", FILE_WRITE);
    if (!file) {
      Serial.println("Failed to open file for writing");
      return;
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 23:51:04