Lua读取数据优化

数据文件

当我们处理数据文件的,一般来说,写文件比读取文件内容来的容易。因为我们可以很好的控制文件的写操作,而从文件读取数据常常碰到不可预知的情况。一个健壮的程序不仅应该可以读取存有正确格式的数据还应该能够处理坏文件(译者注:对数据内容和格式进行校验,对异常情况能够做出恰当处理)。正因为如此,实现一个健壮的读取数据文件的程序是很困难的。

正如我们在 Section 10.1(译者:第 10 章 Complete Examples)中看到的例子,文件格式可以通过使用 Lua 中的 table 构造器来描述。我们只需要在写数据的稍微做一些做一点额外的工作,读取数据将变得容易很多。方法是:将我们的数据文件内容作为 Lua 代码写到 Lua 程序中去。通过使用 table 构造器,这些存放在 Lua 代码中的数据可以像其他普通的文件一样看起来引人注目。

为了更清楚地描述问题,下面我们看看例子.如果我们的数据是预先确定的格式,比如 CSV(逗号分割值),我们几乎没得选择。(在第 20 章,我们介绍如何在 Lua 中处理CSV 文件)。但是如果我们打算创建一个文件为了将来使用,除了 CSV,我们可以使用Lua 构造器来我们表述我们数据,这种情况下,我们将每一个数据记录描述为一个 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({…})等价,他是一个以表作为唯一参数的函数调用。所以,前面那段数据在 Lua 程序中表示如上。如果要读取这个段数据,我们只需要运行我们的Lua 代码。例如下面这段代码计算数据文件中记录数:

local count = 0 
function Entry (b) count = count + 1 end
dofile("data") 
print("number of entries: " .. count) 
下面这段程序收集一个作者名列表中的名字是否在数据文件中出现,如果在文件中出现则打印出来。(作者名字是 Entry 的第一个域;所以,如果 b 是一个 entry 的值,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 处理数据文件中的每一记录都回调用它。当数据文件的大小不是太大的情况下,我们可以使用 name-value 对来描述数据:

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,这并不奇怪。Lua 中构造器正是根据来自 BibTeX的灵感实现的)这种格式我们称之为自描述数据格式,因为每一个数据段都根据他的意思简短的描述为一种数据格式。相对 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
现在,记录域的顺序无关紧要了,甚至某些记录即使不存在 author 这个域,我们也只需要稍微改动一下代码即可:

function Entry (b) 
if b.author then authors[b.author] = true end
end 

Lua 不仅运行速度快,编译速度也快。例如,上面这段搜集作者名的代码处理一个2MB 的数据文件时间不会超过 1 秒。另外,这不是偶然的,数据描述是 Lua 的主要应用之一,从 Lua 发明以来,我们花了很多心血使他能够更快的编译和运行大的 chunks。

发布了268 篇原创文章 · 获赞 153 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39885372/article/details/104367490