一些开发者看到术语 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 格式。