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

ArduinoJson如何将名称匹配的JSON对象所有成员复制到二维数组

实现方案

1 先修正结构体定义

你当前的struct cocktailData定义存在容量不足的问题:char portions[7][1]每个元素仅分配1字节存储空间,既无法存储长度超过1的原料名字符串,也无法存储大于127的数值,需要先调整为符合存储需求的结构:

struct cocktailData
{
  char name[25]; // 存储选中的鸡尾酒名称
  // 按你的需求,最多支持7种原料(你描述的8种对应索引0-7的话可以把7改成8)
  char portions[8][2][25]; // 第一维:原料索引0-7;第二维:0存原料名、1存用量的字符串形式;第三维:单条内容最长24字符
  uint8_t ingredientCnt; // 实际读取到的原料数量,方便后续调用
} data;

如果不需要把用量存为字符串,也可以拆分为两个独立数组,内存占用更低、调用更方便:

struct cocktailData
{
  char name[25];
  char ingredientNames[8][25]; // 存储原料名
  int portionValues[8]; // 存储数值型用量乘数
  uint8_t ingredientCnt;
} data;

以下示例代码采用拆分数组的结构,内存占用更低、调用更方便

2 前置准备

  • 确保你的JSON文件格式正确:你提供的示例中Americano的三个键值对之间缺少英文逗号,会导致解析失败,修正后的正确片段:
"Americano": {
  "campari": 1,
  "red vermouth": 2,
  "soda": 3
},
  • 安装ArduinoJson V6版本库(Arduino库管理器可直接搜索安装)

3 完整实现代码

#include <SPI.h>
#include <SD.h>
#include <ArduinoJson.h>

// 定义结构体
struct cocktailData
{
  char name[25];
  char ingredientNames[8][25];
  int portionValues[8];
  uint8_t ingredientCnt;
} data;

// SD卡CS引脚,根据自己的板子调整,UNO默认是D10
const int SD_CS_PIN = 10;

void setup() {
  Serial.begin(115200);
  
  // 初始化SD卡
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("SD卡初始化失败");
    return;
  }
  
  // 调用读取配方函数,目标鸡尾酒为Americano
  if (loadCocktailRecipe("Americano")) {
    Serial.print("成功读取配方:");
    Serial.println(data.name);
    Serial.print("原料数量:");
    Serial.println(data.ingredientCnt);
    // 遍历打印所有原料和用量
    for (int i=0; i<data.ingredientCnt; i++) {
      Serial.print(data.ingredientNames[i]);
      Serial.print(" : ");
      Serial.println(data.portionValues[i]);
    }
  } else {
    Serial.println("读取配方失败");
  }
}

void loop() {
  // 你的业务逻辑
}

// 加载指定名称的鸡尾酒配方,成功返回true,失败返回false
bool loadCocktailRecipe(const char* targetCocktailName) {
  // 打开JSON文件
  File jsonFile = SD.open("/cocktails.json");
  if (!jsonFile) {
    Serial.println("无法打开cocktails.json文件");
    return false;
  }

  // 分配JSON解析缓冲区,大小根据你的JSON总大小调整,这里给2KB足够存示例内容
  DynamicJsonDocument doc(2048);
  DeserializationError error = deserializeJson(doc, jsonFile);
  // 用完就关闭文件,节省内存
  jsonFile.close();

  if (error) {
    Serial.print("JSON解析失败:");
    Serial.println(error.f_str());
    return false;
  }

  // 获取Cocktails对象
  JsonObject cocktailsObj = doc["Cocktails"];
  // 检查目标鸡尾酒是否存在
  if (!cocktailsObj.containsKey(targetCocktailName)) {
    Serial.print("未找到指定鸡尾酒:");
    Serial.println(targetCocktailName);
    return false;
  }

  // 先清空原有结构体数据
  memset(&data, 0, sizeof(data));
  // 保存鸡尾酒名称
  strncpy(data.name, targetCocktailName, sizeof(data.name)-1);

  // 获取目标鸡尾酒的配方对象
  JsonObject recipeObj = cocktailsObj[targetCocktailName];
  uint8_t index = 0;

  // 遍历配方的所有键值对
  for (JsonPair kv : recipeObj) {
    // 最多支持8种原料,超出就停止遍历
    if (index >= 8) break;
    // 拷贝原料名
    strncpy(data.ingredientNames[index], kv.key().c_str(), sizeof(data.ingredientNames[index])-1);
    // 保存用量
    data.portionValues[index] = kv.value().as<int>();
    index++;
  }
  // 保存实际原料数量
  data.ingredientCnt = index;

  return true;
}

4 代码说明

  • 如果你坚持要用二维数组存储portions,只需要在遍历的时候把原料名存到data.portions[index][0],把用量转为字符串后存到data.portions[index][1]即可
  • 如果你需要支持更多配方,可以调大DynamicJsonDocument的容量,ArduinoJson官网提供了容量计算器可以直接计算所需大小
  • 代码中所有字符串拷贝都预留了结束符位置,避免内存溢出

内容的提问来源于stack exchange,提问作者Jeebus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:27:00