`
webcenterol
  • 浏览: 906777 次
文章分类
社区版块
存档分类
最新评论

数据/配置 的存储方式 Lua篇

 
阅读更多

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

前言

在《数据/配置 的存储方式 Json篇 以JsonCpp库使用为例 》《数据/配置 的存储方式 Json篇 以Cocos2D For Iphone+TouchJson为例 》中我总结了一下怎么使用Json作为配置,但是,其实Json虽然语法格式简单,同时解析库的使用也非常简单,但是,因为这种简单性,缺少有的时候的确非常需要的功能。比如配置文件中对另一行配置的引用,比如配置段的继承等,这些可以使用XML来解决,另外,有的时候还会需要在配置文件中进行简单的运算,比如我就常常会有想将某个图片缩放到目前分辨率的几分之几这样的需求,此时,用一个完整的可以进行运算的语言来做配置的诱惑实在太大了。。。。。。
Lua就是为此而生的。。。。。。虽然现在Lua的功能已经远远不止这样了,但是最初设计Lua的目的就是一个简单的配置语言。见Lua的历史 。虽然其实用Python作为配置也完全可行,但是Lua有着速度快的优点,而且,Lua实在比Python小太多了,很适合嵌入到程序中去。

对于使用Lua作为配置,事实上就相当于在C++中嵌入Lua,只不过不用其脚本语言的一些复杂特性,仅仅将其作为一个配置文件来看。

这里还是以原来《数据/配置 的存储方式 Json篇 以JsonCpp库使用为例 》文中开始的SDL工程作为例子。

首先搭建可以内嵌使用Lua的C++编译环境,下载一个luabinaries 是简单的办法,现在我使用的是lua5_1_4_Win32_dll8_lib.zip 。这里我甚至不需要一个可以运行的Lua交互环境。。。。。

简单示例

首先建立一个简单的Lua文件,命名为picture.lua
name="dragon.png"
rotation=180

虽然只有简单的两行,也是个合法的Lua程序。

然后在C++程序中读取出来,这个过程实际上是使用了Lua的C API,具体的Lua的C API这里就不详细讲解了,那比较复杂,可以参考《Programming in Lua》,中文版也已经有了。这里仅仅作为一个例子提供参考吧。
现在可以开始完成C++的程序了:
首先,包含必要的头文件:
extern "C" {
#include "lua/lua.h"
#include "lua/lauxlib.h"
#include "lua/lualib.h"
}
因为lua的头文件完全是只考虑C语言的情况,所以在C++中使用的时候需要自己添加extern "C"。这是典型的对C++不屑的态度,因为现在大部分的纯C语言写的库,都会很自然的通过宏判断来自动使用extern "C"语句。

然后:
using namespace std;
struct PictureInfo {
string name;
float rotation;
}gPictureInfo;

void PictureInit() {
lua_State *L = luaL_newstate();
if ( luaL_dofile(L, "picture.lua" ) != 0 ) {
printf("Error happen." );
// handle the error.
exit(1 );
}

lua_getglobal(L, "name" );
assert(lua_isstring(L, -1 ) == 1 );

gPictureInfo.name = lua_tostring(L, -1 );

lua_getglobal(L, "rotation" );
gPictureInfo.rotation = (float )lua_tonumber(L, -1 );

lua_close(L);
}
这里我们使用的所有变量全部都是global的变量,所以调用起来非常方便。上面的主要内容就是对Lua C API的使用,由于其本身较为复杂,这里一下也讲不清楚。
基本流程是创建新的Lua state,然后用luaL_dofile 执行我们需要的配置文件,然后调用lua_getglobal 加适当的转换来获取我们需要的配置值。这里的例子是一个字符串和一个浮点数。
具体显示的效果和其他代码参考《数据/配置 的存储方式 Json篇 以JsonCpp库使用为例 》就好了,这里不重复描述了。

数组

在Lua中数组也通过table的形式来表示,这里我仅仅介绍怎么从lua文件中获取配置,具体的显示等东西也不再累述了。
这里,我们建立一个包含数组的lua文件作为配置:

data = {
{ name="dragon.png" , rotation=180 } ,
{ name="dragon.png" , rotation=0 }
}

下面看怎么将配置读取出来:

using namespace std;
struct PictureInfo {
string name;
float rotation;
};

vector gPictureInfoVec;

void PictureInit() {
lua_State *L = luaL_newstate();
if ( luaL_dofile(L, "picture.lua" ) != 0 ) {
printf("Error happen." );
// handle the error.
exit(1 );
}

// get the table
lua_getglobal(L, "data" );
assert(lua_istable(L, -1 ) == 1 );

/* table is in the stack at index 't' */
lua_pushnil(L);/* first key */
while (lua_next(L, -2 ) != 0 ) {
PictureInfo info;
/* 'key' (at index -2) and 'value' (at index -1) */

// push the key to stack for getting the value
lua_pushstring(L, "name" );

// now the table is in the -2 and key in the top(-1)
lua_gettable(L, -2 );
assert(lua_isstring(L, -1 ));

info.name = lua_tostring(L, -1 );

lua_pop(L, 1 );

// push the key to stack for getting the value
lua_pushstring(L, "rotation" );

// now the table is in the -2 and key in the top(-1)
lua_gettable(L, -2 );
assert(lua_isnumber(L, -1 ));

info.rotation = lua_tonumber(L, -1 );

gPictureInfoVec.push_back(info);
/* removes the key we pushed and the 'value' of the global table ; keeps 'key' for next iteration */
lua_pop(L, 2 );
}

lua_close(L);
}

代码中的注释解释的已经够详细了,但是因为Lua 的API的确不是太容易理解,这里也无法一下讲清楚,所以还是先了解Lua 的 API为好,具体的API的意义可以参考参考手册
上面仅仅使用了Lua API遍历数组以及从table中获取元素的方法。
假如仅仅只有上面这些,是看不出用lua作为配置的好处的,用lua做配置的好处在于可以利用lua的特性实现配置段之间的继承以及完整的运算功能。
比如说,完全不用修改上面的读取配置的代码,我们仅仅修改配置,看看在Lua中使用上述功能:

data1 = { name="dragon.png" , rotation=180 }
data2 = { name = data1.name, rotation = data1.rotation / 2 }
data = {
data1, data2
}

此时,data2的数据完全依赖于data1的数据,当有任何东西需要修改的时候,你只需要修改一个地方,对于配置来说,don't repeat yourself也是很有意义的。最最重要的的是,在配置中能够进行计算那是非常强大,即使完全不用lua的函数功能与代码的交互,仅仅通过lua的计算,也可以完成游戏中所有sprite的布局。。。。。。

小结

相对于使用XML,Json,使用Lua作为配置绝对是最最强大的。。。。。。作为一个完整的语言,它拥有你想在配置中实现的一切功能。但是缺点也是很明显的:
首先,速度上,Lua需要解释运行,可能明显跟不上XML或者Json的解析速度。但是,配置的解析读取可以都放在初始化阶段,所以配置不是太多的时候,也不算太过难以接受,另外,还可以将lua的配置完全作为开发期的一种机制使用,在发布后完全转化为2进制数据。
其次,Lua的配置读取需要手动调用Lua的API来完成,相对于XML,Json那种有很方便的库的情况,使用上还是麻烦一些,特别是Lua的API的使用并不是那么简单易懂,不算太直观。但是,这也不是不可以克服的,完全可以自己写个小型的库将Lua的API封装起来,形成一个类似JsonCpp那样的库,用Map来表示一切。这个可能需要限制一些Lua语法的时候,或者在解析的时候进行取舍,比如函数啥的可能需要过滤掉,不然那就不太像将Lua作为配置使用了。
还有,Lua的配置的生成更加是没有XML,Json那样有完善库支持来的方便,这点暂时没有办法克服,写一个自动生成Lua配置文件的库感觉并不是太过容易的事情。而且,自动生成时,lua的优势其实并没有余地发挥出来,那样的话,还不如使用Json。
总的来说,假如是没有工具,需要大量手写配置的话,对Lua的API进行一层简单的封装,然后使用Lua来做配置,那还是件很爽的事情,需要手写的时候,你才会感觉到一个完整语言作为配置给你带来的好处。

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie






分享到:
评论

相关推荐

    lua+nginx动态更新配置.zip

    更新频率比较慢,使用lua_shared_dict进行存储。如下定义: lua_shared_dict sysconfig 10k; 成员包括: "time":配置文件的生成的时间戳(用来判断文件是否有更新)eg:1585209315 "kxsip":与可信控制服务数据交互...

    LuaTableOptimizer, 简单的只读lua表优化器.zip

    LuaTableOptimizer, 简单的只读lua表优化器 LuaTableOptimizer简单的只读lua表优化器Lua表通常用于存储游戏的配置数据。 如果包含许多具有相同值的字段,则需要大量内存。 这种优化可以提高内存使用和加载速度。特性...

    cocos2dx的lua扩展

    - M 就是 Model 层,存储数据的地方,只提供2种接口,gets 和 sets 接口。 - V 就是 View 层,界面显示的地方,处理界面的显示并提供 update 接口(提供给 controller 调用)来更新界面。 - C 就是 Controller 层,...

    esp-idf-lua:ESP-IDF 的 Lua 组件

    Lua 是动态类型的,通过使用基于寄存器的虚拟机解释字节码来运行,并具有带增量垃圾收集的自动内存管理,使其成为配置、脚本和快速原型设计的理想选择。如何使用将此存储库克隆到您项目的components子目录中: cd ~...

    lua-resty-mlcache:OpenResty的分层缓存库

    结合 API和,可以将该库作为键/值存储缓存标量Lua类型和表,从而提供了一种性能且灵活的缓存解决方案。 特征: 使用TTL进行缓存和否定缓存。 通过内置的互斥可以防止在缓存未命中时对数据库/后端产生狗堆效应。 ...

    Panau-Survival-Server:JC2MP服务器Panau Survival的所有服务器代码

    将存储库克隆到您的JC2MP服务器目录中。 在服务器的配置IKnowWhatImDoing设置为true。 如果您之前已经运行过服务器,请删除server.db以确保重新启动。 编辑scripts/inventory/server/sLootManager.lua第5行,并将...

    redis-service:java spring redies:订阅发布系统;统一配置管理; lua脚本实现分布式锁;缓存应用(连接池,切片连接池,哨兵模式)

    统一配置管理 lua脚本实现分布式锁; 缓存应用(连接池,切片连接池,哨兵模式) 备注:哨兵,分片,最大化 哨兵模式集群(一主多从):每个节点拥有所有数据,内存限制 | 改进(解决内存问题) | 分片多主多从:...

    解决nginx+lua搭建文件上传下载服务问题

    项目需要做一个文件上传下载服务,利用 nginx+lua 做一个代理服务,上传入口统一,分发到不同的机器存储,下载链接和物理存储隔离,支持添加 agent 的方式扩容,这里主要讲一下思路和搭建配置过程,大神勿喷。...

    ajlua:Java和Android原生Lua的移植

    CMake在此存储库中配置本native/目录。 例如$ cmake ../native $ make install ( $ make -j install可以加快速度) (本机部分测试) $ ctest在make之后。 $ ctest -V获取更多数据分析结果。 (Java部分) ...

    heka-config-sample:我在生产开发中使用的一些 heka 配置

    我主要使用这个存储库来测试我的配置。 基本上,所有 lua 模块都应该符号链接到/usr/share/heka/<dir>/*.lua 然后,我使用 2 种 heka 实例: 代理:它在我的 DC 的每个节点上运行。 它接受来自 nginx、symfony 的...

    基于微信小程序的互动打卡小程序(java)wlw hsg.zip

    技术栈:Java语言:作为后端开发语言,用于处理业务逻辑和数据存储。Spring Boot框架:用于简化Spring应用的开发和部署,提高开发效率。MyBatis框架:用于简化数据库操作,实现对MySQL数据库的访问。Redis缓存:用于...

    开涛高可用高并发-亿级流量核心技术

    21.4 数据存储实现 410 21.4.1 商品基本信息SSDB集群配置 410 21.4.2 商品介绍SSDB集群配置 413 21.4.3 其他信息Redis配置 417 21.4.4 集群测试 418 21.4.5 Twemproxy配置 419 21.5 动态服务实现 422 21.5.1 项目...

    cassandra-nginx-cdn:一些配置文件和POC代码,用于将Apache Cassandra用作跨多个数据中心的HLS块的分布式存储,并使用脚本将UDP MPEG-TS转换为HLS,反之亦然。 这个想法来自Globo.com的FIFA 14世界杯直播视频平台

    cassandra-nginx-cdn 一些配置文件和POC代码将Apache Cassandra用作跨多个数据中心的HLS块的分布式存储,并使用脚本将UDP MPEG-TS转换/转码为HLS,反之亦然。 这个想法来自Globo.com的FIFA 14世界杯直播视频平台。 ...

    Redis的持久化存储redis-storage.zip

    用luajit替换LUA,增强lua执行性能 author: 七夜, shenzhe QQ: 531020471 QQ群: 62116204(已满) QQ群: 154249567 (未满) mail: lijinxing@gmail.com, shenzhe163@gmail.com ...

    单点登录源码

    - 一站式支付解决方案,统一下单接口,支持支付宝、微信、网银等多种支付方式。不涉及业务的纯粹的支付平台。 - 统一下单(统一下单接口、统一扫码)、订单管理、数据分析、财务报表、商户管理、渠道管理、对账系统...

    CCSim:紧凑型国家模拟器; 一个十几岁的小小的实验性Lua脚本,可模拟国际关系

    如果执行此操作,请确保使用Lua 5.2(而不是LuaJIT)配置Torch安装! JIT解释器无法解决CCSim使用的内存量。 文件格式 作为随机生成数据的替代方法,CCSim支持使用带有预定国家/地区数据的文本文件作为其模拟基础...

    mewa:使用Lua编写编译器前端的编译器编译器

    梅瓦 Mewa是用于快速编译编译器前端原型的编译器编译器。 您使用一种自定义语言(一种Bison / Yacc风格的BNF)编写语法。 您可以指定Lua函数调用,... 它提供了一个数据结构, 和一个内存映射来存储和检索范围绑定的数

    基于SpringCloud、SpringBoot敏捷开发框架SuperBoot.zip

    无缝集成MongoDB数据库,提供对非结构型数据存储,解决关系型数据库瓶颈问题。集成swagger框架,实现自动API测试及调试功能,解决程序员最反感的编写技术文档的问题。数据源基于Druid,提供更高性能及SQL监控。框架...

    lookaround:学习环顾四周

    请参阅SUN360 / config.lua来配置输入和输出目录等的位置。 该存储库包含位于SUN360 / data / minitorchfeed / pixels_trn_torchfeed.h5的示例数据文件,以演示输入HDF5文件的外观。 为了能够开箱即用地运行代码,...

    redis单机配置文档

    Redis(全称:Remote Dictionary Server 远程字典服务)Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列...

Global site tag (gtag.js) - Google Analytics