object库,提供运行时对象支持,通过引用计数维护所有对象。只要是继承自tb_object_t的对象类型都是可以经过扩展实现序列化和反序列化。
库内部也已经提供了常用的对象类型:
- tb_object_data_t: 数据对象类型
- tb_object_date_t: 日期对象类型
- tb_object_null_t: 空值对象类型
- tb_object_array_t: 数组对象类型
- tb_object_string_t: 字符串对象类型
- tb_object_number_t: 数值对象类型,包括浮点、整型
- tb_object_boolean_t: 布尔对象类型
- tb_object_dictionary_t: 字典对象类型
可以看到,基本上这些对象已经可以进行常用数据维护了,和apple的CoreFoundation内部的常用对象很类似,而且可以很方便的扩展其他自定义类型的序列化,这部分等以后再细讲吧。。。
现在先简单看下如何快速解析一个json文件到内存:
// 从文件读取json数据到内存,json_root为整个根对象
tb_object_ref_t json_root = tb_object_read_from_url("/home/file/json.txt");
// 从http读取json数据到内存,json_root为整个根对象
// tb_object_ref_t json_root = tb_object_read_from_url("http://localhost/file/json.txt");
// 从数据读取json数据到内存,json_root为整个根对象
// tb_object_ref_t json_root = tb_object_read_from_data(data, size);
// 从stream读取json数据到内存,json_root为整个根对象
// tb_object_ref_t json_root = tb_object_read(stream);
if (json_root)
{
// 将json_root的所有数据格式打印到终端,一般调试使用
tb_object_dump(json_root);
// 释放json_root对象,object跟CoreFoundation一样是有引用计数的
// 这里json_root没有被其他引用,所以会被立马释放掉
tb_object_exit(json_root);
}
怎么样简单吧,如果要解析plist文件, 也是类似,只需换成plist 文件的url就行了 库内部回去自动检测文件格式,进行相应地解析工作,上层都是通用的object对象树 并且可以支持xplist(xml格式)、bplist(二进制格式)两种格式。
tb_object_ref_t plist_root = tb_object_read_from_url("/home/file/file.plist");
对于序列化到文件,也很简单:
// 序列化json object到文件, size 为实际序列化的字节数,如果失败,返回:-1
// 默认格式存储,通过 tab 和 换行 进行了格式化,方便查看
tb_long_t size = tb_object_writ_to_url(object, "/home/file/json.txt", TB_OBJECT_FORMAT_JSON);
// 序列化json object到文件, size 为实际序列化的字节数,如果失败,返回:-1
// 并且压缩存储,去掉冗余的空白字符
tb_long_t size = tb_object_writ_to_url(object, "/home/file/json.txt", TB_OBJECT_FORMAT_JSON | TB_OBJECT_FORMAT_DEFLATE);
// 序列化json object到数据buffer,size 为实际序列化的字节数,如果失败,返回:-1
tb_byte_t data[8192] = {0};
tb_long_t size = tb_object_writ_to_data(object, data, 8192, TB_OBJECT_FORMAT_JSON);
其他格式类似,如下是可以支持的序列化格式:
- TB_OBJECT_FORMAT_BIN:tbox内部二进制序列化格式,最为节省空间,并且对字符串做了些简单的加密,可以扩展自定义的数据类型
- TB_OBJECT_FORMAT_BPLIST:apple的二进制plist格式,内部字符串为明文,并且空间利用率不是很高
- TB_OBJECT_FORMAT_XPLIST:apple的xml文本plist格式
- TB_OBJECT_FORMAT_XML:tbox内部的xml文本序列化格式,可以扩展自定义的数据类型
- TB_OBJECT_FORMAT_JSON:json序列化格式
object对象的字段解析有两种模式,一种是一层层迭代遍历,一种是直接定位到指定字段 迭代遍历,只有array和dictionay需要,他们同样是支持tbox容器库的迭代器模式的,例如:
// 遍历array
tb_for_all (tb_object_ref_t, item, tb_object_array_itor(array))
{
if (item)
{
// ...
}
}
// 遍历dictionary
tb_for_all (tb_object_dictionary_item_t*, item, tb_object_dictionary_itor(dictionary))
{
// 获取dictionary的每一个键值对
if (item)
{
// 键名字符串
tb_char_t const* key = item->key;
// 值对象, 可以继续迭代下层或直接取值
tb_object_ref_t val = item->val;
// ...
}
}
如果要直接定位某个字段,可以使用tbox的seek模式,支持自定义路径格式:
/* 例如对于这个xml的数据解析
<dict>
<key>string</key>
<string>hello wolrd!</string>
<key>com.xxx.xxx</key>
<string>hello wolrd!</string>
<key>integer</key>
<number>31415926</number>
<key>array</key>
<array>
<string>hello wolrd!</string>
<number>31415926</number>
<number>3.1415926</number>
<false/>
<true/>
<dict>
<key>string</key>
<string>hello wolrd!</string>
</dict>
</array>
</dict>
* 其对应的字段路径:
* 1. ".string" : hello wolrd!
* 2. ".array[1]" : 31415926
* 3. ".array[5].string" : hello wolrd!
* 4. ".com\\.xxx\\.xxx" : hello wolrd!
*/
/* seek到指定路径:.array[5].string ,进行解析字段
*
* 这里传TB_OBJECT_TYPE_STRING作为最后一个参数,是为了内部做一次类型检测
* 如果这个字段确实string类型的,才会返回对象,否则返回null,这样上层解析代码
* 看上去更加的简洁,不需要每次解析一个字段,都要外面做一下检测类型
*
* 如果传TB_OBJECT_TYPE_NONE进去,那么不管是不是string对象,都会返回成功
* 这个时候上层如果不做类型检测,只是去字符串,库内部会有断言,但是不影响程序逻辑
* 仅仅是提示下,你现在的处理类型有误。
*/
tb_object_ref_t object = tb_object_seek(object, ".array[5].string", TB_OBJECT_TYPE_STRING);
if (object)
{
tb_trace_d("%s", tb_object_string_cstr(object));
}
其他字段的解析:
/* 解析string类型字段, 取值前,先做类型判断是最安全的方式
* 虽然直接转换也是安全的,类型不对内部直接会返回tb_null
* 但是为了养成良好的编程习惯,在调试模式下,库内部会有检测断言提示类型不匹配
*/
if (tb_object_type(object) == TB_OBJECT_TYPE_STRING)
{
tb_char_t const* string = tb_object_string_cstr(object);
}
// 解析number类型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_NUMBER)
{
// 获取整型值,如果不是会自动强转,有可能丢失精度
tb_uint32_t value = tb_object_number_uint32(object);
// 获取浮点值,如果不是会自动强转
// tb_float_t value = tb_object_number_float(object);
// 获取双精度浮点值,如果不是会自动强转
// tb_double_t value = tb_object_number_double(object);
}
// 解析boolean类型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_BOOLEAN)
{
// 获取bool值
tb_bool_t value = tb_object_boolean_bool(object);
}
// 解析data类型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_DATA)
{
// 获取数据指针
tb_byte_t* data = tb_object_data_getp(object);
// 获取数据大小
tb_size_t size = tb_object_data_size(object);
}
// 解析date类型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_DATE)
{
// 获取时间戳
tb_time_t time = tb_object_date_time(object);
}
// 解析array类型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_ARRAY)
{
// 获取成员数量
tb_size_t count = tb_object_array_size(object);
tb_size_t i = 0;
for (i = 0; i < count; i++)
{
tb_object_ref_t item = tb_object_array_item(object, i);
}
}
// 解析dictionary类型字段
if (tb_object_type(object) == TB_OBJECT_TYPE_DICTIONARY)
{
// 获取对象键值
tb_object_ref_t value = tb_object_dictionary_val(object, "key_name");
}