在游戏中加载解析配置文件家常便饭。以前用过xml,对多维数组结构良好的应用加上xml配置文件遵循html规则,xml还是特别方便的,可是当数据量比较大的话,一堆助记符不仅写起来比较烦,出现问题查起来很费眼睛。今天用一种新的文件解析方式,语法挺简单的,但真正将这个小型库配置到自己的工程里还是费了不少力气。
由于这几天一直在看boost库,boost库的话通过设置包含目录,在自己的文件里引用hpp文件就能很轻松的使用里面的函数,方法。在思维惯性的作用下,继续包含josn头文件,结果悲剧的一天开始了,开始报错说“无法解析的外部符号 "public: __thiscall Json::Value::~Value(void)" (??1Value@Json@@QAE@XZ),该符号在函数 _wmain 中被引用”,很明显就是说对函数进行了申明,但没有定义,很常见的问题。那就将cpp文件包含到工程里,由于h文件是放在include目录下的,在配置里被包含了。可cpp我并没有放在include文件下,提示错误没有包含stdax.h文件,异常郁闷。。。。。。大家知道在vs建立的新工程都要包含stdax.h文件,所以手动将库文件stdax.h是手动加到库文件里,编译通过了。但感觉不妥啊,库文件不应给改啊!!!到这里想到了包含lib文件的方式。
大概看了下文档,lib文件就是所谓的静态链接文件,名字看着挺吓人。其实就是将函数导成一种新的文件,包含到工程中,编译的时候调用,还有一种dll文件就是所谓的动态链接文件。程序运行的时候链接的文件。好吧,终于明白了什么是lib文件,如何生成lib文件又是个问题,找了半天文档,发现在vs的配置属性里可以改变输出文件类型,分别有exe,lib,dll类型的文件。生成lib文件后再包含到工程里,但是编译提示找不到相应的lib文件,什么情况 -_-!,想想肯定是路径问题了,将lib文件放到了工作目录,但在vs配置里添加的lib文件,编译器会去根目录找这个文件。我是真心无语啊,这ide确实大大提高了工作效率,但不可否认的是,如果对ide不熟悉的话,遇到问题能害死人。还有推荐尽量用#pragma comment(lib, "test.lib")包含库文件吧。这样自己test.lib放到哪都没问题,自己可以任意放到自己喜欢的目录(最好还是放到工作目录。。。。。)。库文件加上了,结果又跑出个json源文件生成的库文件和系统默认的库文件冲突,msvcrt.lib,选择将系统库msvcrt.lib忽略,编译通过。但这种方式很是不爽,想想用包含文件的方法,之前json头文件在配置属性里已经包含在x:/include里了,在工程里添加文件夹include然后将json实现文件cpp都添加进来,编译通过。哦,终于明白了,这个文件夹不能乱起,要和配置文件里的名字一样,这样编译器在编译的时候直接能找到对应的实现文件。好吧,问题终于解决了,总结一下用个库得知道多少知识。
1、什么是库
2、如何将库添加到工程
3、什么是工程工作目录,什么工程根目录
4、编译器编译时寻找文件的方式
5、库文件冲突和解决办法
6、什么是虚拟映射
好吧,这些障碍扫清后再来看json文件配置和解析方法,这个可以参考官方文档,我这里大致说说我的理解。json里有两种符号:一种是"{}",另一种是“[]”。大括号一个对象,中括号表示一个数组。比如说 在配置文件写下{"name" : "xiaoy", "age" : 17},然后看代码,如何加载、打印这个对象。
#include "stdafx.h" #include <iostream> #include <fstream> #include "json\json.h" using namespace std; int _tmain(int argc, char* argv[]) { fstream file("test.json"); if (!file) { cout<<"Open file test.json fail!!!"<<endl; } Json::Value root; Json::Reader reader; if (!reader.parse(file, root, false)) { cout<<"Parse error"<<endl; } string name = root["name"].asString(); int age = root["age"].asInt(); cout<<"name:"<<name<<"\tage:"<<age<<endl; getchar(); return 0; }
看见了吗,root就如c++里map,这样是不是很方便。配置文件也很简单。
再看一下,数组的用法。json配置文件为[{"name" : "xiaoy", "age" :17} , {"name" : "xiaot", "age" : 20}],代码如下:
#include "stdafx.h" #include <iostream> #include <fstream> #include "json\json.h" using namespace std; int _tmain(int argc, char* argv[]) { fstream file("test.json"); if (!file) { cout<<"Open file test.json fail!!!"<<endl; } Json::Value root; Json::Reader reader; if (!reader.parse(file, root, false)) { cout<<"Parse error"<<endl; } int size = root.size(); for (int i = 0; i < size; ++i) { string name = root[i]["name"].asString(); int age = root[i]["age"].asInt(); cout<<"age:"<<age<<"\tname:"<<name<<endl; } getchar(); return 0; }
看到了吧,这次区别是root变成一个数组了,遍历数组就可以了,注意数据和对象之间都要用","隔开。当然了实际中肯定有更加复杂的数据结构,到时活学活用吧。