lua学习笔记(4)——lua配置文件和table使用

作为配置语言是lua的一个重要应用,lua文件在配置应用中非常灵活,可以直接读取文件中的全局量的值,也可以读取表以及嵌套表。

一、lua使用方式

个人理解,根据应用的场景和复杂程度,可以分为以下几种情况:

1、场景较简单,lua文件中使用全局量配置值

如:test.lua

-- configguration file for probram c

width = 200
height = 300
background_red = 0.30
background_green = 0.10
background_blue = 0

配置文件中都全局量,加载文件后,直接读取相应的值。

此种方式应用简单,但配置较多较复杂时,文件就会比较大,而且不方便分类。

2、场景较复杂,配置进行了分类,则lua文件中使用全局量+table(表)的方式进行配置

如:test.lua

-- configguration file for probram c

width = 200;

height = 300;

white =

{

r = 0;

g = 0;

b = 0;

}

blue =

{

r = 0;

g = 0;

b =

{

br =

{

brr = 110

};

bg = 11;

bb = 12;

}

}

black =

{

r = 1;

g = 1;

b = 10;

}

配置文件中有全局量,也有table(表),表之间还可以多重嵌套。简单的配置通过读取全局量获取,其他配置可以进行分类成表,再细分嵌套的表等。

3、场景复杂,针对不同版本不同客户进行分类,每一个版本下面的配置又要细分,则使用多个文件进行配置,公有的配置放在一个文件中,不同的配置放在不同的lua文件中,然后包含公有的lua文件(类似C中的include,但有差异)

如:global.lua

-- gllbal config

width = 200;

height = 300;

test.lua

dofile("../global.lua");  -- 把文件包含进来

white =

{

r = 0;

g = 0;

b = 0;

}

blue =

{

r = 0;

g = 0;

b =

{

br =

{

brr = 110

};

bg = 11;

bb = 12;

}

}

black =

{

r = 1;

g = 1;

b = 10;

}

此种方式可以灵活按照不通客户不通类型进行分类,配置使用灵活,可以满足绝大部分应用场景。

二、Lua配置文件使用

前面的学习中进行了基础的api操作,也熟悉了编写套路。

使用lua配置文件的基本步骤:

1、open lua环境 (lua_open

2、加载标准库函数(luaL_openlibs

3、加载lua文件并编译执行(luaL_loadfilelua_pcall

4、读取全局量和table

5、嵌套table的处理(类似C中的二维数组)

读取table有两种方法,后面会介绍。

示例代码:

int load(char *filename, int *width, int *height)
{
    lua_State *L = lua_open();

    luaL_openlibs(L);  /* 打开lua包,加载标准库函数 */

    /* 加载文件后,仅仅是将文件内容编译,在栈顶形成一个匿名函数,
    调用lua_pcall调用该函数后,文件的内容才执行,之后才能访问全局量和函数等*/
    if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
    {
        printf("cannot run configuration file :%s\n", lua_tostring(L, -1));
        return 0;
    }

    /* 获取全局变量的值,每调用一次就把获取的值入栈 */
    lua_getglobal(L, "width");
    lua_getglobal(L, "height");

    if(lua_isnumber(L, -2))
    {
        *width = (int)lua_tonumber(L, -2);
        printf("width:%d\n", *width);
    }
    else
    {
        printf("width shoule be a number\n");
    }

    if(lua_isnumber(L, -1))
    {
        *height = (int)lua_tonumber(L, -1);
        printf("height:%d\n", *height);
    }
    else
    {
        printf("height shoule be a number\n");
    }
    
    return 0;
}

int main(void)
{
    int width = 0, height = 0;

    load("test.lua", &width, &height);
    
    return 0;
}


三、读取table的方法

下面使用的lua文件如下:
-- configuration file for program 'pp'
width = 200; 
height = 300;

white = 
{
	r = 0;
	g = 0;
	b = 0;
}

blue = 
{
	r = 0;
	g = 0;
	b = 
	{
		br = 
		{
			brr = 110
		};
		bg = 11;
		bb = 12;
	}
}

black = 
{
	r = 1;
	g = 1;
	b = 10;
}

下面假设:t[K], t table k 为表中我们要取值的标识,即 key。
1、通过键值获取

lua_getglobal(L, t);    /* 此处获取全局量,这里的全局量是一个table */
lua_pushstring(L, k);  /* 将要取值的key入栈,这里类型对应,如lua_pushstringlua_pushnumber*/
lua_gettable(L, -2);   /* 该函数取下表指定的table,然后将刚刚的key出栈并取得对应的值后,入栈,此时值在栈顶 */

lua_tostring(L, -1);   /* 获得值 */

lua_pop(L, 1);       /* 获得值后,将值出栈,还原原来的栈 */

嵌套的表也是类似的,每一次取值操作都会有入栈出栈操作,取值后会恢复原来的栈,所以不会破坏原来的栈。

看例子,跟踪栈的情况。

未嵌套:

C代码:

int load_table(char *filename, char *table)
{
    lua_State *L = lua_open();

    luaL_openlibs(L);  /* 打开lua包,加载标准库函数 */

    /* 加载文件后,仅仅是将文件内容编译,在栈顶形成一个匿名函数,
    调用lua_pcall调用该函数后,文件的内容才执行,之后才能访问全局量和函数等*/
    if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
    {
        printf("cannot run configuration file :%s\n", lua_tostring(L, -1));
        return 0;
    }
    
    printf("stack 001:\n");
    stackdump(L);

    /* 获取全局变量的值,每调用一次就把获取的值入栈 */
    lua_getglobal(L, "width");
    lua_getglobal(L, "height");
    
    printf("stack 002:\n");
    stackdump(L);

    lua_getglobal(L, table);
    
    printf("stack 003:\n");
    stackdump(L);

    printf("//////////////\n");
    
    lua_pushstring(L, "b");
    printf("stack 003.1:\n");
    stackdump(L);

    lua_gettable(L, -2);
    printf("stack 003.2:\n");
    stackdump(L);
    
    lua_pushstring(L, "g");
    printf("stack 003.3:\n");
    stackdump(L);

    lua_gettable(L, -3);
    printf("stack 003.4:\n");
    stackdump(L);

    lua_pop(L, 1);
    lua_pop(L, 1);
    printf("stack 003.5:\n");
    stackdump(L);
    printf("/////////////////\n");

    lua_close(L);
        
    return 0;
}

int main(void)
{
    load_table("test.lua", "black");
    
    return 0;
}

运行结果:

$ ./lua_test

stack 001:

stack 002:

200   300   

stack 003:

200   300   table   

//////////////

stack 003.1:

200   300   table   b   

stack 003.2:

200   300   table   10   

stack 003.3:

200   300   table   10   g   

stack 003.4:

200   300   table   10   1   

stack 003.5:

200   300   table   

/////////////////

嵌套table

C代码:

int load_table(char *filename, char *table)
{
    lua_State *L = lua_open();

    luaL_openlibs(L);  /* 打开lua包,加载标准库函数 */

    /* 加载文件后,仅仅是将文件内容编译,在栈顶形成一个匿名函数,
    调用lua_pcall调用该函数后,文件的内容才执行,之后才能访问全局量和函数等*/
    if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
    {
        printf("cannot run configuration file :%s\n", lua_tostring(L, -1));
        return 0;
    }
    
    printf("stack 001:\n");
    stackdump(L);

    /* 获取全局变量的值,每调用一次就把获取的值入栈 */
    lua_getglobal(L, "width");
    lua_getglobal(L, "height");
    
    printf("stack 002:\n");
    stackdump(L);

    lua_getglobal(L, table);
    
    printf("stack 003:\n");
    stackdump(L);

    printf("//////////////\n");
    
    lua_pushstring(L, "b");
    printf("stack 003.1:\n");
    stackdump(L);

    lua_gettable(L, -2);
    printf("stack 003.2:\n");
    stackdump(L);

    lua_pushstring(L, "br");
    printf("stack 003.2.1:\n");
    stackdump(L);

    
    lua_gettable(L, -2);
    printf("stack 003.2.2:\n");
    stackdump(L);
    
    lua_pushstring(L, "g");
    printf("stack 003.3:\n");
    stackdump(L);

    lua_gettable(L, -3);
    printf("stack 003.4:\n");
    stackdump(L);

    lua_pop(L, 1);
    lua_pop(L, 1);
    lua_pop(L, 1);
    printf("stack 003.5:\n");
    stackdump(L);
    printf("/////////////////\n");

    lua_close(L);
        
    return 0;
}

int main(void)
{
    load_table("test.lua", "blue");
    return 0;
}

运行结果:

$ ./lua_test

stack 001:

stack 002:

200   300   

stack 003:

200   300   table   

//////////////

stack 003.1:

200   300   table   b   

stack 003.2:

200   300   table   table   

stack 003.2.1:

200   300   table   table   br   

stack 003.2.2:

200   300   table   table   table   

stack 003.3:

200   300   table   table   table   g   

stack 003.4:

200   300   table   table   table   nil   

stack 003.5:

200   300   table   

/////////////////

2、遍历table

lua_getglobal(L, t);
lua_pushnil(L);
while (lua_next(L, -2)) {
/* 此时栈上 -1 处为 value, -2 处为 key */
lua_pop(L, 1); /* 取值后将值出栈,还原原来的栈 */
}

 

测试发现这种遍历方式是从后往前遍历的。

C代码:

int load_table(char *filename, char *table)
{
    lua_State *L = lua_open();

    luaL_openlibs(L);  /* 打开lua包,加载标准库函数 */

    /* 加载文件后,仅仅是将文件内容编译,在栈顶形成一个匿名函数,
    调用lua_pcall调用该函数后,文件的内容才执行,之后才能访问全局量和函数等*/
    if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
    {
        printf("cannot run configuration file :%s\n", lua_tostring(L, -1));
        return 0;
    }
    
    printf("stack 001:\n");
    stackdump(L);

    /* 获取全局变量的值,每调用一次就把获取的值入栈 */
    lua_getglobal(L, "width");
    lua_getglobal(L, "height");

    
    printf("stack 002:\n");
    stackdump(L);

    lua_getglobal(L, table);
    
    printf("stack 003:\n");
    stackdump(L);
    lua_pushnil(L);

    while(lua_next(L, -2))
    {
        printf("stack 004:\n");
        stackdump(L);

        lua_pop(L, 1);
        printf("stack 004:\n");
        stackdump(L);
    }

    lua_close(L);
        
    return 0;
}

int main(void)
{
    load_table("test.lua", "black");
    
    return 0;
}

运行结果:

 $ ./lua_test
stack 001:


stack 002:
200   300   
stack 003:
200   300   table   
stack 004:
200   300   table   b   table   
stack 004:
200   300   table   b   
stack 004:
200   300   table   g   0   
stack 004:
200   300   table   g   
stack 004:
200   300   table   r   0   
stack 004:
200   300   table   r   


这里仅仅是给出了基本的操作方法,更复杂的 配置也是有这些基本的操作方法+字符串解析等实现。

到这里,lua作为配置用在C的基本操作和用法就学完了。


写这边文章参考了几篇大神的文章:

读取table

http://www.jb51.net/article/58479.htm

https://www.cnblogs.com/billyrun/articles/5768627.html

C API函数介绍:

http://blog.csdn.net/yuliying/article/details/43412355


猜你喜欢

转载自blog.csdn.net/xiaofeng881105/article/details/78595115