跳转至

JSON 数据处理(json)

作者:马梦阳 | 最后修改:2026-08-19

一、json 概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它易于人类阅读和编写,同时也易于机器解析和生成。JSON 基于 JavaScript 编程语言的一个子集,但独立于语言,目前已被广泛应用于各种编程环境之间的数据交换。

在 LuatOS 中,json 库提供了将 Lua 对象与 JSON 字符串相互转换的能力,开发者可以借助 json 库轻松实现设备与服务器之间的数据交互。

1.1 JSON 的基本结构

1.1.1 对象

对象是一个无序的键值对集合,以左花括号 { 开始,以右花括号 } 结束,键值对之间使用逗号分隔,键与值之间使用冒号分隔。例如:

{"name": "luatos", "version": 1.0}

1.1.2 数组

数组是一个有序的值集合,以左方括号 [ 开始,以右方括号 ] 结束,值之间使用逗号分隔。例如:

["luatos", 1.0, true]

1.2 JSON 的优点

JSON 具有以下优点:

1、简洁性:JSON 的语法简单,数据量小,易于阅读和编写;

2、可移植性:JSON 与编程语言无关,可以在不同语言和平台之间进行数据交换;

3、灵活性:JSON 支持嵌套结构,可以表示复杂的数据关系。

1.3 常用场景

JSON 常用于以下场景:

1、设备与云平台之间的数据上报与下发;

2、配置文件的数据存储与读取;

3、接口调用时的请求参数与响应结果。

二、演示功能概述

本 demo 使用 Air724UG 核心板搭配 json 库演示 json 序列化与反序列化功能,包含以下两个模块:

1、main.lua:主程序入口;

2、json_app.lua:json 序列化与反序列化功能模块。

演示分为两部分:

1、将 Lua 对象转为 JSON 字符串:

  • 示例一:Lua string 转为 JSON string;

  • 示例二:Lua number 转为 JSON string;

  • 示例三:Lua boolean 转为 JSON string;

  • 示例四:Lua table 转为 JSON string;

  • 示例五:Lua nil 转为 JSON string;

  • 序列化失败示例和指定浮点数示例。

2、将 JSON 字符串转为 Lua 对象:

  • 示例一:JSON string 转为 Lua string;

  • 示例二:JSON number 转为 Lua number;

  • 示例三:JSON boolean 转为 Lua boolean;

  • 示例四:JSON table 转为 Lua table;

  • 示例五:JSON nil 转为 Lua nil;

  • 反序列化失败示例;

  • 空表(empty table)转换为 JSON 时的说明;

  • 字符串中包含控制字符(如 \r\n)的 JSON 序列化与反序列化说明;

  • json.null 的语义与比较行为说明。

三、准备硬件环境

1、Air724UG 核心板一块

Air724UG核心板

2、TYPE-C USB 数据线一根

3、Air724UG 核心板和数据线的硬件接线方式为:

  • Air724UG 核心板通过 TYPE-C USB 口连接 TYPE-C USB 数据线,数据线的另外一端连接电脑的 USB 口;

  • Air724UG 核心板通过 TYPE-C USB 口供电。

Air724UG 核心板购买链接:合宙官方淘宝店铺

四、准备软件环境

4.1 软件环境

在开始实践本示例之前,先筹备一下软件环境:

1、烧录工具:Luatools 下载调试工具

2、本 demo 开发测试时使用的固件为 Air724 LuatOS 固件,本 demo 对固件版本没有什么特殊要求,所以你如果要测试本 demo 时,可以直接使用最新版本的内核固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本 demo 时使用的内核固件版本来对比测试;

3、脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air724/demo/json

4、lib 脚本文件:使用 Luatools 烧录时,勾选「添加默认 lib」选项,使用默认 lib 脚本文件。

准备好软件环境之后,接下来查看 如何烧录项目文件到 Air724UG 核心板,将本篇文章中演示使用的项目文件烧录到 Air724UG 核心板中。

4.2 API 介绍

json 库:https://docs.openluat.com/osapi/core/json/

五、程序结构

json/
│── main.lua
│── json_app.lua
│── readme.md

5.1 文件说明

1、main.lua:主程序入口文件,负责定义项目名和版本号、加载业务模块,最后调用 sys.run() 启动 LuatOS 运行框架。

2、json_app.lua:json 序列化与反序列化功能模块,演示将 Lua 对象转为 JSON 字符串、将 JSON 字符串转为 Lua 对象。

六、代码详解

6.1 main.lua

主程序文件 main.lua 是整个项目的入口点。它负责定义 PROJECT 和 VERSION 变量、打印项目信息、加载业务模块,最后调用 sys.run() 启动 LuatOS 运行框架。

--[[
@module  main
@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑
@version 1.0
@date    2025.11.05
@author  马梦阳
@usage

本demo演示的核心功能为:
1.将 Lua 对象 转为 JSON 字符串:
    示例一:Lua string 转为 JSON string;
    示例二:Lua number 转为 JSON string;
    示例三:Lua boolean 转为 JSON string;
    示例四:Lua table 转为 JSON string;
    示例五:Lua nil 转为 JSON string;
    序列化失败示例和指定浮点数示例;
2.将 JSON 字符串 转为 Lua 对象:
    示例一:JSON string 转为 Lua string;
    示例二:JSON number 转为 Lua number;
    示例三:JSON boolean 转为 Lua boolean;
    示例四:JSON table 转为 Lua table;
    示例五:JSON nil 转为 Lua nil;
    反序列化失败示例;
    空表(empty table)转换为 JSON 时的说明;
    字符串中包含控制字符(如 \r\n)的 JSON 序列化与反序列化说明;
    json.null 的语义与比较行为说明:

更多说明参考本目录下的 readme.md 文件;
]]


--[[
必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
PROJECT:项目名,ascii string类型
        可以随便定义,只要不使用,就行
VERSION:项目版本号,ascii string类型
        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
            X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
            因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为999
        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
]]
PROJECT = "json"
VERSION = "001.999.000"


-- 在日志中打印项目名和项目版本号
log.info("main", PROJECT, VERSION)




-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
-- 启动errDump日志存储并且上传功能,600秒上传一次
-- if errDump then
--     errDump.config(true, 600)
-- end


-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
-- 可以使用合宙的iot.openluat.com平台进行远程升级
-- 也可以使用客户自己搭建的平台进行远程升级
-- 远程升级的详细用法,可以参考fota的demo进行使用


-- 启动一个循环定时器
-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
-- 方便分析内存使用是否有异常
-- sys.timerLoopStart(function()
--     log.info("mem.lua", rtos.meminfo())
--     log.info("mem.sys", rtos.meminfo("sys"))
-- end, 3000)


-- 加载 json 应用模块
require "json_app"


-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

6.2 json_app.lua

json_app.lua 是 json 序列化与反序列化功能模块,核心业务逻辑为:

1、将 Lua 对象转为 JSON 字符串(序列化):演示 string、number、boolean、table、nil 五种类型,以及序列化失败示例和指定浮点数示例;

2、将 JSON 字符串转为 Lua 对象(反序列化):演示 string、number、boolean、table、nil 五种类型,以及反序列化失败示例、空表说明、控制字符说明、json.null 说明。

6.2.1 序列化:将 Lua 对象转为 JSON 字符串

使用 json.encode(data) 将 Lua 对象转为 JSON 字符串。若转换失败,会返回 nil 值,并通过 err_msg 参数返回错误信息,强烈建议在使用时添加额外的判断。

示例一:Lua string 转为 JSON string;

local data = "test"
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("string_string_test1", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("string_string_test1", "序列化成功:", json_str)
end

示例二:Lua number 转为 JSON string;

local data = 123456789
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("number_string_test1", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("number_string_test1", "序列化成功:", json_str)
end

示例三:Lua boolean 转为 JSON string;

local data = true
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("boolean_string_test1", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("boolean_string_test1", "序列化成功:", json_str)
end

示例四:Lua table 转为 JSON string;

local data = {abc = 123, def = "123", ttt = true}
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("table_string_test1", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    -- 由于 Lua 表在遍历时键的顺序是不确定的(尤其是字符串键)
    -- 而 JSON 对象本身也是无序的
    -- 因此序列化后的 JSON 字符串中键的顺序可能与 Lua 源码中的书写顺序不同,属于正常情况
    log.info("table_string_test1", "序列化成功:", json_str)
end

示例五:Lua nil 转为 JSON string;

local data = nil
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("nil_string_test1", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    -- 注意:此时返回值是一个空字符串 ""
    log.info("nil_string_test1", "序列化成功:", json_str)
end

序列化失败示例:Lua table 中包含 function;

local data = {abc = 123, def = "123", ttt = true, err = function() end}
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("table_string_test2", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("table_string_test2", "序列化成功:", json_str)
end

指定浮点数示例:指定保留三位小数,不足时补零,超出时四舍五入;

local data = {abc = 1234.56789}
local json_str, err_msg = json.encode(data, "3f")
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("table_string_test3", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("table_string_test3", "序列化成功:", json_str)
end

6.2.2 反序列化:将 JSON 字符串转为 Lua 对象

使用 json.decode(str) 将 JSON 字符串转为 Lua 对象。若转换失败,会返回 nil 值,并通过 err 参数返回错误信息,强烈建议在使用时添加额外的判断。

示例一:JSON string 转为 Lua string;

local str = '"test"'
local obj, result, err = json.decode(str)
if result == false then
    -- 反序列化失败时, 会返回 nil 值, 并通过 err 参数返回错误信息
    log.info("string_string_test1", "反序列化失败:", err)
else
    -- 反序列化成功时, 会返回 Lua string
    log.info("string_string_test1", "反序列化成功:", obj)
end

示例二:JSON number 转为 Lua number;

local str = "123456789"
local obj, result, err = json.decode(str)
if result == false then
    -- 反序列化失败时, 会返回 nil 值, 并通过 err 参数返回错误信息
    log.info("string_number_test1", "反序列化失败:", err)
else
    -- 反序列化成功时, 会返回 Lua number
    log.info("string_number_test1", "反序列化成功:", obj)
end

示例三:JSON boolean 转为 Lua boolean;

local str = "true"
local obj, result, err = json.decode(str)
if result == false then
    -- 反序列化失败时, 会返回 nil 值, 并通过 err 参数返回错误信息
    log.info("string_boolean_test1", "反序列化失败:", err)
else
    -- 反序列化成功时, 会返回 Lua boolean
    log.info("string_boolean_test1", "反序列化成功:", obj)
end

示例四:JSON string 转为 Lua table;

local str = "{\"abc\":1234545}"
local obj, result, err = json.decode(str)
if result == false then
    -- 反序列化失败时, 会返回 nil 值, 并通过 err 参数返回错误信息
    log.info("string_table_test1.2", "反序列化失败:", err)
else
    -- 反序列化成功时, 会返回 Lua table
    -- 注意:此时 obj 是一个 Lua table
    -- 若直接打印 obj,会输出 table: 01C9A490 类似的内存地址
    log.info("string_table_test1.2", "反序列化成功:", obj)
    -- 需要添加具体的字段名称,才能正确输出
    log.info("string_table_test1.2", "反序列化成功:", obj.abc)
end

反序列化失败示例:JSON string 不是合法的 JSON 格式;

local str = "{\"def\":}"
local obj, result, err = json.decode(str)
if result == false then
    -- 反序列化失败时, 会返回 nil 值, 并通过 err 参数返回错误信息
    log.info("string_table_test2", "反序列化失败:", err)
else
    -- 反序列化成功时, 会返回 Lua table
    log.info("string_table_test2", "反序列化成功:", obj)
end

空表(empty table)转换为 JSON 时的说明:

原生 Lua 中的 table 是数组(sequence)和哈希表(map)的统一数据结构。空表 {} 在转换为 JSON 时存在歧义:无法确定应输出为空数组 [] 还是空对象 {}。由于 Lua 中只有包含连续正整数索引(从 1 开始)的表才被视为数组,而空表不满足这一条件,因此 JSON 库默认将其序列化为 {}(空对象);

local data = {abc = {}}
local json_str, err_msg = json.encode(data)
if json_str == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("table_string_test3", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("table_string_test3", "序列化成功:", json_str)
end

字符串中包含控制字符(如 \r\n)的 JSON 序列化与反序列化说明:

在 Lua 中,字符串可以包含任意字符,包括回车(\r)、换行(\n)等控制字符。当使用 json.encode() 对包含此类字符的字符串进行序列化时,JSON 库会自动将其转义为标准 JSON 字符串字面量形式(例如 \r 转为 "\r",\n 转为 "\n"),以确保生成的 JSON 符合规范且可安全传输。反序列化时(json.decode()),这些转义序列会被正确还原为原始的控制字符,因此解码后的字符串与原始字符串在内容上完全一致(逐字节相等);

local tmp = "ABC\r\nDEF\r\n"
local tmp2, err_msg = json.encode({str = tmp})
if tmp2 == nil then
    -- 序列化失败时, 会返回 nil 值, 并通过 err_msg 参数返回错误信息
    log.info("json", "序列化失败:", err_msg)
else
    -- 序列化成功时, 会返回 JSON 字符串
    log.info("json", "序列化成功:", tmp2)
end
local tmp3, result, err = json.decode(tmp2)
if result == false then
    -- 反序列化失败时, 会返回 nil 值, 并通过 err 参数返回错误信息
    log.info("json", "反序列化失败:", err)
else
    -- 反序列化成功时, 会返回 Lua table
    -- 注意:此时 tmp3 是一个 Lua table
    -- 直接打印 tmp3 显示的是内存地址,需要添加对应字段
    -- true 前存在一个空格长度,这是日志输出格式导致的,与字符串内容本身无实际差异
    log.info("json", "反序列化成功:", tmp3.str, tmp3.str == tmp)
end

json.null 的语义与比较行为说明:

在标准 JSON 中,null 是一个合法的字面量,表示"空值"或"无值"。然而,Lua 语言本身没有 null 类型,只有 nil 用于表示未定义或空值。为在 Lua 中准确表示 JSON 的 null,json 库提供了一个特殊占位符:json.null。当使用 json.encode() 序列化包含 json.null 的字段时,该字段会被正确转换为 JSON 中的 null;反之,json.decode() 在解析 JSON 中的 null 时,会将其还原为 json.null,而非 Lua 的 nil。这是因为若将 JSON 的 null 直接转为 nil,会导致 table 中对应键被删除,从而丢失原始 JSON 的结构信息。由于 json.null 是一个具体的值(非 nil),它与 nil 比较结果为 false,只有与 json.null 自身比较时结果才为 true。开发者应始终使用 == json.null 来判断某个字段是否为 JSON 的 null,而不要用 == nil,否则逻辑将出错;

log.info("json.null", json.encode({name = json.null}))
-- 日志输出:{"name":null}
log.info("json.null", json.decode("{\"abc\":null}").abc == json.null)
-- 日志输出:true
log.info("json.null", json.decode("{\"abc\":null}").abc == nil)
-- 日志输出:false

七、运行结果展示

出现类似于下面的日志,就表示运行成功:

[00000001.009] I/user.string_string_test1 序列化成功: "test"
[00000001.009] I/user.number_string_test1 序列化成功: 123456789
[00000001.010] I/user.boolean_string_test1 序列化成功: true
[00000001.010] I/user.table_string_test1 序列化成功: {"abc":123,"ttt":true,"def":"123"}
[00000001.010] I/user.nil_string_test1 序列化成功:
[00000001.011] I/user.table_string_test2 序列化失败: Cannot serialise function: type not supported
[00000001.011] I/user.table_string_test3 序列化成功: {"abc":1234.568}
[00000001.011] I/user.string_string_test1 反序列化成功: test
[00000001.011] I/user.string_number_test1 反序列化成功: 123456789
[00000001.011] I/user.string_boolean_test1 反序列化成功: true
[00000001.011] I/user.string_table_test1.2 反序列化成功: table: 01FE5010
[00000001.011] I/user.string_table_test1.2 反序列化成功: 1234545
[00000001.011] I/user.string_table_test2 反序列化失败: Expected value but found T_OBJ_END at character 8
[00000001.012] I/user.table_string_test3 序列化成功: {"abc":{}}
[00000001.012] I/user.json 序列化成功: {"str":"ABC\r\nDEF\r\n"}
[00000001.012] I/user.json 反序列化成功: ABC
DEF
 true
[00000001.012] I/user.json.null {"name":null}
[00000001.012] I/user.json.null true
[00000001.012] I/user.json.null false

八、总结

通过本文学习,你可以掌握 json 序列化与反序列化的使用方法,了解 Lua 对象与 JSON 字符串之间的转换规则、失败处理方式,以及空表、控制字符、json.null 等特殊场景的处理方式,为后续学习更加复杂的业务逻辑打下基础。

搜索