用Lua解析配置文件(教程)

2,725 阅读3分钟

并非所有的应用程序都需要配置文件;许多应用程序在每次启动时都能从新开始。例如,简单的实用程序,很少需要在不同的使用中持续的偏好或设置。然而,当你编写一个复杂的应用程序时,用户能够配置他们如何与它互动以及它如何与他们的系统互动是很好的。这就是配置文件的作用,本文讨论了一些可以用Lua编程语言实现持久化设置的方法。

选择一种格式

配置文件的重要之处在于它们的一致性和可预测性。你不希望在保存用户偏好的名义下,把信息倒入一个文件,然后花几天时间写代码来反向处理文件中随机出现的信息。

有几种流行的配置文件格式。Lua有用于大多数常见配置格式的库;在这篇文章中,我将使用INI格式。

安装库

Lua库的中心枢纽是Luarocks.org。你可以在网站上搜索库,或者你可以安装并使用luarocks 终端命令。

在Linux上,你可以从你的发行版的软件库中安装它。比如说。

$ sudo dnf install luarocks

在macOS上,使用MacPortsHomebrew。在Windows上,使用Chocolatey

一旦luarocks ,你可以使用search 子命令来搜索一个合适的库。如果你不知道一个库的名字,你可以搜索一个关键词,比如inixmljson ,这取决于与你要做的事情有关的内容。在这种情况下,你可以直接搜索inifile ,这是我用来解析 INI 格式文本文件的库。

$ luarocks search inifile
Search results:
inifile
 1.0-2 (rockspec) - https://luarocks.org
 1.0-2 (src) - https://luarocks.org
 1.0-1 (rockspec) - https://luarocks.org
 [...]

程序员经常陷入的一个陷阱是在他们的系统上安装一个库,却忘记了将它与他们的应用程序捆绑在一起。这可能会给没有安装该库的用户带来问题。为了避免这种情况,使用--tree 选项将库安装到你的项目目录下的本地文件夹中。如果你没有一个项目目录,先创建一个,然后再安装。

$ mkdir demo
$ cd demo
$ luarocks install --tree=local inifile

--tree 选项告诉luarocks 创建一个新的目录,在本例中称为local ,并将你的库安装到其中。通过这个简单的技巧,你可以把你的项目使用的所有依赖性代码直接安装到项目目录中。

代码设置

首先,在一个名为myconfig.ini 的文件中创建一些INI数据。

[example]
name=Tux
species=penguin
enabled=false

[demo]
name=Beastie
species=demon
enabled=false

将该文件作为myconfig.ini 保存在你的主目录下,而_不是_你的项目目录下。你通常希望配置文件存在于你的应用程序之外,这样即使用户卸载了你的应用程序,他们在使用该应用程序时产生的数据仍然在他们的系统中。用户可能会手动删除不必要的配置文件,但很多人不会这样做。结果是,如果他们重新安装一个应用程序,它将保留他们所有的偏好。

配置文件的位置在技术上是不重要的,但每个操作系统(OS)都有一个规范或传统,说明它们应该放在哪里。在Linux上,这是由Freedesktop规范定义的。它规定,配置文件应保存在一个名为~/.config 的隐藏文件夹中。在这个练习中,为了清晰起见,只需将文件保存在你的主目录中,这样就很容易找到和使用。

创建第二个名为main.lua 的文件,并在你最喜欢的文本编辑器中打开它。

首先,你必须告诉Lua你把你希望它使用的附加库放在哪里。package.path 这个变量决定了Lua寻找库的位置。你可以在终端中查看Lua的默认包路径。

$ Lua
> print(package.path)
./?.lua;/usr/share/lua/5.3/?.lua;/usr/share/lua/5.3/?/init.lua;/usr/lib64/lua/5.3/?.lua;/usr/lib64/lua/5.3/?/init.lua

在你的Lua代码中,将你的本地库位置附加到package.path

package.path = package.path .. ';local/share/lua/5.3/?.lua

用Lua解析INI文件

在确定了包的位置后,接下来要做的就是要求inifile 库,然后处理一些操作系统的物流。尽管这是一个简单的示例程序,但代码需要从操作系统获得用户的主目录位置,并在必要时确定如何将文件系统路径传回给操作系统。

package.path = package.path .. ';local/share/lua/5.3/?.lua
inifile = require('inifile')

-- find home directory
home = os.getenv('HOME')

-- detect path separator
-- returns '/' for Linux and Mac
-- and '\' for Windows
d = package.config:sub(1,1)

现在你可以使用inifile ,将配置文件中的数据解析到一个Lua表中。一旦数据被放置到一个表中,你可以像其他Lua表一样查询该表。

-- parse the INI file and
-- put values into a table called conf
conf = inifile.parse(home .. d .. 'myconfig.ini')

-- print the data for review
print(conf['example']['name'])
print(conf['example']['species'])
print(conf['example']['enabled'])

在终端中运行代码以查看结果。

$ lua ./main.lua
Tux
penguin
false

这看起来是正确的。试着对demo 块做同样的事情。

以INI格式保存数据

并非所有的分析器库都能读写数据(通常称为_编码_和_解码_),但inifile 库可以。这意味着你可以用它来对一个配置文件进行修改。

要改变配置文件中的一个值,你要在解析后的表中设置代表该值的变量,然后将该表写回到配置文件中。

-- set enabled to true
conf['example']['enabled'] = true
conf['demo']['enabled'] = true

-- save the change
inifile.save(home .. d .. 'myconfig.ini', conf)

现在来看看这个配置文件吧。

$ cat ~/myconfig.ini
[example]
name=Tux
species=penguin
enabled=true

[demo]
name=Beastie
species=demon
enabled=true

配置文件

保存关于用户想如何使用一个应用程序的数据的能力是编程的一个重要部分。幸运的是,这对程序员来说是一项常见的任务,所以很多工作可能已经完成了。找到一个好的编码和解码成开放格式的库,你就可以提供一个持久的、一致的用户体验。

这里有整个演示代码供参考。

package.path = package.path .. ';local/share/lua/5.3/?.lua'
inifile = require('inifile')

-- find home directory
home = os.getenv('HOME')

-- detect path separator
-- returns '/' for Linux and Mac
-- and '\' for Windows
d = package.config:sub(1,1)

-- parse the INI file and
-- put values into a table called conf
conf = inifile.parse(home .. d .. 'myconfig.ini')

-- print the data for review
print(conf['example']['name'])
print(conf['example']['species'])
print(conf['example']['enabled'])

-- enable Tux
conf['example']['enabled'] = true

-- save the change
inifile.save(home .. d .. 'myconfig.ini', conf)