一些开发者看到术语 JSON 就认为它会很复杂。JSON 的文档最初可能看起来令人生畏,但理解 JSON 的基础知识以及如何使用它来保存/加载数据非常有用。
JSON 代表 JavaScript 对象 表示法。它是开发者在 JavaScript 中定义对象为数组(Lua 中的表)的方式,这些对象使用
| 姓名 | 克拉克·肯特 |
| 昵称 | 超人 |
| 地址 | 大都会 |
| 年龄 | 32 |
如果我们在 Lua 中为这些数据创建一个表,它可能如下所示
local hero = {
name = "Clark Kent",
nickname = "Superman",
address = "Metropolis",
age = 32
}
或者,相同的数据可以用 JSON 表示如下
var hero = {
"name":"Clark Kent",
"nickname":"Superman",
"address":"Metropolis",
"age":32
};
注意 JSON 和 Lua 代码之间的相似之处。在两者中,我们都声明= (Lua): (JSON)true/false) 是可以在 JSON 数据中指定的唯一单个项目 — 您不能包含 Corona 显示对象或任何依赖于用户数据/C 内存的内容。
对于更复杂的表,JSON 还支持在方括号 ([]) 内使用项目数组和在大括号 ({}) 内使用对象。让我们将示例数据扩展到 Lua 数组中的多个英雄
local heroes = {
{ name="Clark Kent", nickname="Superman", address="Metropolis", age=32 },
{ name="Bruce Wayne", nickname="Batman", address="Gotham", age=36 },
{ name="Diana Prince", nickname="Wonder Woman", address="New York", age=28 },
}
或者在 JSON 中…
var heroes = [
{ "name":"Clark Kent", "nickname":"Superman", "address":"Metropolis", "age":32 },
{ "name":"Bruce Wayne", "nickname":"Batman", "address":"Gotham", "age":36 },
{ "name":"Diana Prince", "nickname":"Wonder Woman", "address":"New York", "age":28 },
]
};
再次注意,它与 Lua 非常相似 — 这就是 JSON 在 Lua 开发者中流行的原因之一。与 XML 相比,JSON 的语法也更紧凑和轻量级,在 XML 中,除了数据之外,您还需要开始和结束标签。最后,许多您的应用程序可能连接到的在线服务也使用 JSON。
作为 Corona 开发者,无需完全理解 JSON 即可使用它,因为我们提供了两个方便的 API 调用,作为
使用上面的示例数据,让我们使用 json.encode() 将 Lua 表编码为 JSON,并使用 print() 将其值打印到 Corona 控制台
local json = require( "json" ) -- Include the Corona JSON library
local heroes = {
{ name="Clark Kent", nickname="Superman", address="Metropolis", age=32 },
{ name="Bruce Wayne", nickname="Batman", address="Gotham", age=36 },
{ name="Diana Prince", nickname="Wonder Woman", address="New York", age=28 },
}
local serializedJSON = json.encode( heroes )
print( serializedJSON )
这将输出如下内容
[{"nickname":"Superman","age":32,"name":"Clark Kent","address":"Metropolis"},{"nickname":"Batman","age":36,"name":"Bruce Wayne","address":"Gotham"},{"nickname":"Wonder Woman","age":28,"name":"Diana Prince","address":"New York"}]
现在,要将此 JSON 字符串解码回 Lua 表,只需调用 json.decode() 并使用 print() 将其值打印到控制台。这将输出创建的 Lua 表的典型内存引用,例如table: 0x6080010613c0
local serializedJSON = json.encode( heroes ) print( serializedJSON ) local newHeroes = json.decode( serializedJSON ) print( newHeroes )
通过这两个步骤,我们将 Lua 表转换为 JSON 字符串,然后将其转换回 Lua 表,甚至无需理解 JSON。JSON 就是这么简单!
在 Lua 和 JSON 之间编码和解码数据最有用的目的之一是
如果您需要处理数据库格式的大量数据,或者需要根据不同的参数对数据进行排序和过滤,JSON 则不是理想的解决方案。在这种情况下,请参阅使用 SQLite 访问数据库教程,了解有关如何在 SQLite 数据库中保存、加载和利用数据的详细信息。
让我们从创建一个方便的 Lua 模块来包含必要的函数开始。您可以在Corona 中的外部模块教程中进一步学习这个概念,但基本上我们将从一个典型的设置开始
local M = {}
local json = require( "json" )
local defaultLocation = system.DocumentsDirectory
return M
将此文件保存到您的主项目目录中,名为 loadsave.lua。本质上,这段初始代码设置了一个 Lua 表 M,它将存储我们在以下部分中创建的函数,并返回该表,以便这些函数可以被任何require()system.DocumentsDirectory) 以将 JSON 文件保存/加载到/从该位置。
现在让我们向 loadsave.lua 模块添加一个保存函数
local M = {}
local json = require( "json" )
local defaultLocation = system.DocumentsDirectory
function M.saveTable( t, filename, location )
local loc = location
if not location then
loc = defaultLocation
end
-- Path for the file to write
local path = system.pathForFile( filename, loc )
-- Open the file handle
local file, errorString = io.open( path, "w" )
if not file then
-- Error occurred; output the cause
print( "File error: " .. errorString )
return false
else
-- Write encoded JSON data to file
file:write( json.encode( t ) )
-- Close the file handle
io.close( file )
return true
end
end
return M
此函数相对简单,它遵循读取和写入文件指南中的基本示例。它的工作原理如下
此函数接受三个参数:t、filename 和 location — t 是应转换为 JSON 并保存的 Lua 表,filename 是目标 JSON 文件的名称,location 是保存文件的本地存储位置。
在函数内部,我们首先设置本地存储位置。如果未定义 location 参数,我们将其设置为 defaultLocation (system.DocumentsDirectory),这是 99% 的情况下应该保存文件的位置。
接下来,我们根据 filename 参数和位置创建目标文件的路径。
之后,我们以写入访问权限 ("w") 打开文件句柄,因为我们正在保存(写入)文件。
最后,假设文件句柄有效,我们将json.encode( t ))true。
如果没有将数据加载回内存的方法,保存数据就没有多大用处,所以让我们向 loadsave.lua 模块添加一个加载函数
function M.loadTable( filename, location )
local loc = location
if not location then
loc = defaultLocation
end
-- Path for the file to read
local path = system.pathForFile( filename, loc )
-- Open the file handle
local file, errorString = io.open( path, "r" )
if not file then
-- Error occurred; output the cause
print( "File error: " .. errorString )
else
-- Read data from file
local contents = file:read( "*a" )
-- Decode JSON data into Lua table
local t = json.decode( contents )
-- Close the file handle
io.close( file )
-- Return table
return t
end
end
return M
此函数也很基本
这次只需要两个参数:filename 和 location — filename 是要读取的 JSON 文件的名称,location 是其本地存储位置。
在函数内部,我们首先确定本地存储位置。与 saveTable() 函数一样,除非 location 参数另有指定,否则将其设置为默认值 system.DocumentsDirectory。
接下来,我们根据 filename 参数和位置创建文件的路径。
之后,我们以读取访问权限 ("r") 打开文件句柄,因为我们正在加载(读取)文件。
最后,假设文件句柄有效,我们将文件数据读入 contents 字符串,将其解码回 Lua 表json.decode( contents ))t,以便在调用此函数时返回 Lua 表。
作为一个非常简单的示例,假设我们有一个包含各种游戏设置的表。使用此表,我们可以使用 saveTable() 函数保存数据。这会将 Lua 表编码为 JSON 并将其保存到 system.DocumentsDirectory()(默认)作为 settings.json。
local loadsave = require( "loadsave" )
local gameSettings = {
musicOn = true,
soundOn = true,
difficulty = "easy",
highScore = 10000,
highestLevel = 7
}
loadsave.saveTable( gameSettings, "settings.json" )
然后,要重新加载数据,我们可以使用 loadTable() 函数,请求刚刚保存的文件
local loadedSettings = loadsave.loadTable( "settings.json" )
如果您经常使用多个键/值保存和加载数据,那么表输出函数对于检查加载表中究竟包含什么内容可能非常有用。网上有几个关于这个概念的例子,但在输出表内容教程中可以找到一个经过验证且功能强大的版本。
如本教程所示,JSON 提供了一种轻量级的方法,可以将 Lua 表转换为序列化文本字符串,这些字符串可以在在线服务之间交换或保存到本地文件。然后,只需一行代码,即可将它们恢复为原始 Lua 格式。