第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还将帮助支持 Lua 项目。
![]() |
用 Lua 编程 | ![]() |
| 第二部分。表和对象 第 12 章。数据文件和持久性 |
在处理数据文件时,通常写数据比读回数据容易得多。当我们写文件时,我们可以完全控制正在发生的事情。另一方面,当我们读文件时,我们不知道会发生什么。除了正确文件可能包含的所有类型的数据之外,健壮的程序还应该优雅地处理错误文件。因此,编写健壮的输入例程总是很困难。
正如我们在 第 10.1 节 的示例中所看到的,表构造函数为文件格式提供了一个有趣的替代方案。在写数据时只需稍加工作,读取就会变得非常简单。这种技术是将我们的数据文件写成 Lua 代码,在运行时将数据构建到程序中。使用表构造函数,这些块看起来非常像一个普通数据文件。
和往常一样,让我们看一个示例来阐明问题。如果我们的数据文件采用预定义的格式,例如 CSV(逗号分隔值),我们几乎没有选择。(在 第 20 章 中,我们将看到如何在 Lua 中读取 CSV。)但是,如果我们要创建文件以供以后使用,我们可以使用 Lua 构造函数作为我们的格式,而不是 CSV。在这种格式中,我们将每条数据记录表示为一个 Lua 构造函数。我们不写类似于
Donald E. Knuth,Literate Programming,CSLI,1992
Jon Bentley,More Programming Pearls,Addison-Wesley,1990
这样的内容,而是在数据文件中写
Entry{"Donald E. Knuth",
"Literate Programming",
"CSLI",
1992}
Entry{"Jon Bentley",
"More Programming Pearls",
"Addison-Wesley",
1990}
请记住,Entry{...} 与 Entry({...}) 相同,即调用函数 Entry,其参数是一个表。因此,此先前的这部分数据是一个 Lua 程序。要读取此文件,我们只需要运行它,并为 Entry 提供一个明智的定义。例如,以下程序统计数据文件中的条目数
local count = 0
function Entry (b) count = count + 1 end
dofile("data")
print("number of entries: " .. count)
下一个程序在文件中收集所有作者的姓名,然后打印出来。(作者姓名是每个条目中的第一个字段;因此,如果 b 是一个条目值,b[1] 是作者。)
local authors = {} -- a set to collect authors
function Entry (b) authors[b[1]] = true end
dofile("data")
for name in pairs(authors) do print(name) end
请注意这些程序片段中的事件驱动方法:Entry 函数充当回调函数,在 dofile 期间针对数据文件中的每个条目调用该函数。
当文件大小不是一个大问题时,我们可以使用名称-值对进行表示
Entry{
author = "Donald E. Knuth",
title = "Literate Programming",
publisher = "CSLI",
year = 1992
}
Entry{
author = "Jon Bentley",
title = "More Programming Pearls",
publisher = "Addison-Wesley",
year = 1990
}
(如果此格式让您想起了 BibTeX,那不是巧合。BibTeX 是 Lua 中构造函数语法的灵感来源之一。)这种格式是我们所说的自描述数据格式,因为每条数据都附有对其含义的简短描述。自描述数据比 CSV 或其他紧凑表示法更具可读性(至少对人类而言);必要时,它们很容易手动编辑;并且它们允许我们进行小的修改,而无需更改数据文件。例如,如果我们添加一个新字段,我们只需要对读取程序进行一个小小的更改,以便在字段不存在时提供一个默认值。
使用 name-value 格式,我们收集作者的程序变为
local authors = {} -- a set to collect authors
function Entry (b) authors[b.author] = true end
dofile("data")
for name in pairs(authors) do print(name) end
现在字段的顺序无关紧要。即使某些条目没有作者,我们只需要更改 Entry
function Entry (b)
if b.author then authors[b.author] = true end
end
Lua 不仅运行速度快,而且编译速度也快。例如,用于列出作者的上述程序在 2 MB 的数据中运行时间不到一秒。同样,这不是偶然的。数据描述一直是 Lua 自创建以来主要应用之一,我们非常注意使其编译器对大块数据运行得很快。
| 版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 | ![]() |