Chinaunix

标题: SPDataPickle: C语言的结构体和 xml/json/protobuf 的自动转化(移植到 win32 平台) [打印本页]

作者: iunknown    时间: 2009-01-22 23:06
标题: SPDataPickle: C语言的结构体和 xml/json/protobuf 的自动转化(移植到 win32 平台)
SPDataPickle 是一个用于在 C语言的结构体和 xml/json 之间做自动转化的库。

http://code.google.com/p/spdatapickle
http://spdatapickle.googlecode.c ... ckle-0.5.src.tar.gz

大家可能对 google 的 protocol buffers 都早有耳闻。SPDataPickle 和 protobuf 很相似。

仿照 google protobuf 的例子,也来一个 Person 的简单例子。

对应 a.proto ,要写一个 a.xml

  1. <metainfo prefix="XYZ" filename="account">
  2.     <struct name="Person">
  3.         <field name="id"    type="int32" />
  4.         <field name="name"  type="*char" />
  5.         <field name="email" type="*char" />
  6.     </struct>
  7. </metainfo>
复制代码


然后使用 spxml2struct 处理这个 a.xml,生成具体的 structure 定义和 metainfo 。

  1. enum {
  2.     eTypeXYZPerson = eTypeSPDPUserDefine + 1
  3. };

  4. typedef struct tagXYZPerson {
  5.     int mId;
  6.     char * mName;
  7.     char * mEmail;
  8. } XYZPerson_t;

  9. typedef struct tagSP_DPMetaInfo SP_DPMetaInfo_t;
  10. extern SP_DPMetaInfo_t * gXYZAccountMetaInfo;
复制代码


然后就可以对这个 XYZPerson_t 结构进行序列化和反序列化。

  1. int main( int argc, char * argv[] )
  2. {
  3.     XYZPerson_t person;

  4.     person.mId = 123;
  5.     person.mName = strdup( "Bob" );
  6.     person.mEmail = strdup( "bob@example.com" );

  7.     SP_XmlStringBuffer buffer;

  8.     SP_XmlPickle pickle( gXYZAccountMetaInfo );
  9.     pickle.pickle( &person, sizeof( person ), eTypeXYZPerson, &buffer );

  10.     printf( "xml: %s\n", buffer.getBuffer() );

  11.     XYZPerson_t other;
  12.     pickle.unpickle( buffer.getBuffer(), buffer.getSize(), eTypeXYZPerson, &other, sizeof( other ) );

  13.     printf( "id %d, name %s, email %s\n", other.mId, other.mName, other.mEmail );

  14.     SP_DPAlloc alloc( gXYZAccountMetaInfo );

  15.     alloc.free( &person, sizeof( person ), eTypeXYZPerson );
  16.     alloc.free( &other, sizeof( person ), eTypeXYZPerson );

  17.     return 0;
  18. }
复制代码


输出结果

  1. xml: <Person>
  2. <id>123</id>
  3. <name>Bob</name>
  4. <email>bob@example.com</email>
  5. </Person>

  6. id 123, name Bob, email [email]bob@example.com[/email]
复制代码

[ 本帖最后由 iunknown 于 2009-11-6 23:14 编辑 ]
作者: iunknown    时间: 2009-08-02 18:06
发布 0.2 版本,新增特性
1.增加了对 json 的支持
2.xml pickle 和 json pickle 用一个统一的接口,方便使用
3.在 metainfo 中支持指定某个字段是可选的,在解包的时候,如果对应的字段不存在,直接跳过

http://spdatapickle.googlecode.c ... ckle-0.2.src.tar.gz


  1. <metainfo prefix="XYZ" filename="addrbook">
  2.     <struct name="Email">
  3.         <field name="Type"    type="char" arraysize="10" />
  4.         <field name="Address" type="*char" />
  5.         <field name="Nickname" type="*char" required="0" />
  6.     </struct>
  7. </metainfo>
复制代码


  1. void testEmail( SP_DataPickle * pickle )
  2. {
  3.     XYZEmail_t email;
  4.     memset( &email, 0, sizeof( email ) );

  5.     strncpy( email.mType, "work", sizeof( email.mType ) - 1 );
  6.     email.mAddress = strdup( "foo <[email]foo@bar.com[/email]>" );

  7.     SP_XmlStringBuffer buffer;

  8.     pickle->pickle( &email, sizeof( email ), eTypeXYZEmail, &buffer );

  9.     printf( "%s\n\n", buffer.getBuffer() );

  10.     SP_DPAlloc alloc( gXYZAddrbookMetaInfo );
  11.     alloc.free( &email, sizeof( email ), eTypeXYZEmail );
  12. }
复制代码


序列化的结果

  1. {
  2.         "Email" : {
  3.                 "Type" : "work",
  4.                 "Address" : "foo <[email]foo@bar.com[/email]>"
  5.         }
  6. }
复制代码

[ 本帖最后由 iunknown 于 2009-8-2 18:09 编辑 ]
作者: vbs100    时间: 2009-08-02 18:32
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?
作者: iunknown    时间: 2009-08-02 21:20
原帖由 vbs100 于 2009-8-2 18:32 发表
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?


如果整个系统都是用 C/C++ 的话,那么直接用二进制协议就非常方便。

但事情有另外的一面。这个问题其实相当于是在问 xml和json 存在的理由。
关于这一点,可以看看 xmlrpc 列举的理由:

http://www.xmlrpc.com/spec

Strategies/Goals

Firewalls. The goal of this protocol is to lay a compatible foundation across different environments, no new power is provided beyond the capabilities of the CGI interface. Firewall software can watch for POSTs whose Content-Type is text/xml.

Discoverability. We wanted a clean, extensible format that's very simple. It should be possible for an HTML coder to be able to look at a file containing an XML-RPC procedure call, understand what it's doing, and be able to modify it and have it work on the first or second try.

Easy to implement. We also wanted it to be an easy to implement protocol that could quickly be adapted to run in other environments or on other operating systems.

作者: vbs100    时间: 2009-08-03 08:59
标题: 回复 #4 iunknown 的帖子
存在即合理吧 学习了 可能以后工作上也会遇到
作者: iunknown    时间: 2009-10-07 22:31
标题: 发布 0.3 版本
发布 0.3 版本,新增特性
1.增加了对 ProtoBuf wire format 的支持

http://spdatapickle.googlecode.c ... ckle-0.3.src.tar.gz

这个功能没有使用 google 的代码,而是重新实现了 wire format 的编码解码器。
http://iunknown.javaeye.com/blog/482683

这个实现,比起 google 的更轻量。google 的 protobuf 代码量太大了。
作者: yulihua49    时间: 2009-10-10 16:05
原帖由 vbs100 于 2009-8-2 18:32 发表
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?

在网络上,各种不同系统,二进制不方便。
实际上是用模板映射结构,要很仔细保持模板和结构的关系。
使用xml格式做模板效率较低,在C语言里我更喜欢用结构做模板,其他语言可以用xml。

我也搞了一个JSON的,可以支持SQL和JSON之间的映射。
那里起先叫DTO,后来改称DAU(DATA Access Unit)

数据模板从数据库生成,结构根据模板分配。

DAU_init(DAU,SQL_Connect,tablename,0,0);//后边两个参数=0,要求数据库以表名生成模板和结构,否则,一个是结构,一个是模板。
DAU里包含了数据库连接句柄,表名,结构,模板,还有其他资源。

sprintf(where,"WHERE .....",,,,);
DAU_select(DAU,where,0);//以where里的条件从数据库读。语句是内部生成的(也使用模板)。
DAU_next(DAU);//从结果集中提取1行倒结构;
json=json_object_new_object(); //生成一个空JSON

DAU_toJSON(DAU,json,0);//结构内容进入JSON对象
char *p=json_object_to_json_string(json);//JSON变字符串;这个字符串可以输出了;
。。。。。

下贴1楼是过程,2楼是结果,以后是关于功能和性能的讨论:
http://www.itpub.net/thread-1088197-1-1.html

还没有做XML的,感觉包太大,处理效率较低,在OLTP里不合适。

DAU系统完成 结构-关系映射(有点像JAVA的ORM),结构的序列化是其中一部分内容。所以它的模板比较复杂,完成的功能超过了序列化要求。
看来你的工作与我有类似之处,特来探讨一下。
你也可以考虑模板自动生成的问题,可以依赖数据库进行。

我没有采取XML或JSON定义模板,主要是感觉在一个大型事务系统里,要附带一大堆XML文件挺累赘的,何况这些文件在运行时环境里,万一被改动,程序就死掉不明不白。
我的模板是在编译环境里,运行时看不见。所以安全一些。

上边帖子很长,后边有模板的样式。

[ 本帖最后由 yulihua49 于 2009-10-10 16:49 编辑 ]
作者: sbc19861004    时间: 2009-10-10 16:14
序列化是个说大就大,说小就小的问题,和兼容性,异构度有关,好像json比较受吹捧
作者: yulihua49    时间: 2009-10-10 16:50
原帖由 sbc19861004 于 2009-10-10 16:14 发表
序列化是个说大就大,说小就小的问题,和兼容性,异构度有关,好像json比较受吹捧

json比较轻便,效率也好。我们现在通信协议就用JSON。
比JSON在精简就是传统字符串和分隔符了,双方用同样用模板也可以解析复杂的字符串结构。
字符串还有保密作用,没有模板你很难看懂数据的含义。

[ 本帖最后由 yulihua49 于 2009-10-10 16:54 编辑 ]
作者: flw    时间: 2009-10-10 16:58
原帖由 vbs100 于 2009-8-2 18:32 发表
用c语言序列化成xml/json我觉得是很恶心的事件 为什么不定义个协议用二进制方式传?

二进制不方便调试。
流行的 internet 协议几乎全是文本的,
HTTP FTP SMTP POP
作者: iunknown    时间: 2009-10-11 11:43
原帖由 yulihua49 于 2009-10-10 16:05 发表

在网络上,各种不同系统,二进制不方便。
实际上是用模板映射结构,要很仔细保持模板和结构的关系。
使用xml格式做模板效率较低,在C语言里我更喜欢用结构做模板,其他语言可以用xml。

我也搞了一个JSON ...



这个自动序列化的关键,就在于要在 c/c++ 实现类似 java 的反射机制。
java 的反射机制,是由于在语言级别为每个类生成了 metainfo ,我们可以直接使用。
c/c++ 中,对于 structure 默认没有生成 metainfo ,因此需要我们自己来生成。

spdatapickle 中,xml 文件在运行时是不需要的,只是在编译期需要。
通过 xml 文件的描述,自动生成 structure ,同时生成 structure 的 metainfo ,
可以确保 structure 和 metainfo 是对应的。这些 metainfo 就在 dp_xyzaddrbook.cpp 文件中。

这些 metainfo ,主要信息包含 structure 中各个字段的类型,名称,偏移位置,编号。
有了这些信息,就可以遍历一个 structure 的所有字段,这就相当于具有了 java 中的反射机制。

有了这套反射机制,很多 java 中能做的事情,在 c/c++ 中都是可以做的。比如 java 的自动序列化,或者 ORM 。


关于 DTO ,从下面的连接来看
http://space.itpub.net/8804348/viewspace-478471

里面提到的映射模板,是要人工手写么?这个映射模板,就相当于上面提到的 metainfo 。
在 spdatapickle 里面,这个 metainfo 是通过从 xml 描述中自动生成的,同时由于 structure 也是从 xml 描述生成的,
因此可以保证 structure 和 metainfo 是完全一致的。


  1. SRM的映射模板,相当于iBates的映像文件:
  2. T_PkgType seat_type[] = {                /* 席位表 */
  3.         {CH_DATE,YEAR_TO_DAY_LEN,"start_date",YEAR_TO_DAY,-1}, /* 始发日期 YYYY-MM-DD*/
  4.         {CH_CHAR,5,"beg_station"},        /* 上车站 */
  5.         {CH_CHAR,13,"Train_no"},        /* 始发车次 */
  6.         {CH_CHAR,7,"run_train"},        /* 运行车次 */
  7. ......
  8.         {-1,0,0}
  9. };
复制代码


对应 spdatapickle 里面,生成的 metainfo 类似是这样



  1. 自动生成的结构体

  2. typedef struct tagXYZPhoneNumber {
  3.     char mType[10];
  4.     int mPrimary;
  5.     char * mContent;
  6. } XYZPhoneNumber_t;

  7. 自动生成的 metainfo

  8. static SP_DPMetaField_t gMetaXYZPhoneNumber [] = {
  9.     { sizeof(SP_DPMetaField_t), 1, "Type",                             
  10.        // 第一个字段是这个 metafield 本身的大小,为以后扩展留下余地。 第二个字段是 编号,在 protobuf 中用到。第三个是字段名。
  11.         SP_DP_FIELD_OFFSET(XYZPhoneNumber_t, mType), eTypeSPDPChar, 1, 1, 10,
  12.        // 第四个字段是这个字段在结构体中的偏移位置。第五个字段是字段类型。第六个字段表明是否指针。
  13.        // 第七个字段表示是否为必要字段。第8个字段表明是否定为数组。
  14.         "", sizeof(char[10]), sizeof(char), 0 },
  15.         // 第九个字段用于指针类型中,指明指针指向的内容的长度。第十个字段表明这个字段的总大小。第十一个字段表明这个字段每个元素的大小。
  16.         // 第十二个字段表明,这个字段是否为用于指明另外一个字段长度的。
  17.     { sizeof(SP_DPMetaField_t), 2, "Primary",
  18.         SP_DP_FIELD_OFFSET(XYZPhoneNumber_t, mPrimary), eTypeSPDPInt32, 0, 1, 0,
  19.         "", sizeof(int), sizeof(int), 0 },
  20.     { sizeof(SP_DPMetaField_t), 3, "Content",
  21.         SP_DP_FIELD_OFFSET(XYZPhoneNumber_t, mContent), eTypeSPDPChar, 1, 1, 0,
  22.         "", sizeof(char *), sizeof(char), 0 }
  23. };
复制代码

[ 本帖最后由 iunknown 于 2009-10-11 12:02 编辑 ]
作者: iunknown    时间: 2009-10-11 11:52
原帖由 sbc19861004 于 2009-10-10 16:14 发表
序列化是个说大就大,说小就小的问题,和兼容性,异构度有关,好像json比较受吹捧



类似 google protobuf 定义的 wire format ,在兼容性方面其实是很好的。
它的格式设计,已经充分考虑了异构的平台。

二进制的格式,对于传输大量的数据,请求非常频繁的场景下,相对于文本还是有一些性能上的好处的。

json 相对于 xml ,在有效负载方面的确有明显的优势。
劣势可能就在于不像 xml 那样,有 ms,ibm 这些大公司在后面推广。
作者: iunknown    时间: 2009-11-06 23:14
标题: 发布 0.5 版本,移植到 win32 平台
发布 0.5 版本,包括
1.protobuf 的一些 bugfix
2.移植到 win32 平台

http://spdatapickle.googlecode.c ... ckle-0.5.src.tar.gz
作者: emacsnw    时间: 2009-11-07 13:17
原帖由 iunknown 于 2009-1-22 07:06 发表
SPDataPickle 是一个用于在 C语言的结构体和 xml/json 之间做自动转化的库。

http://code.google.com/p/spdatapickle
http://spdatapickle.googlecode.c ... ckle-0.5.src.tar.gz

大家可能对 ...


大概看了一下代码。有个疑问。
假如用你的代码来实现RPC。传入的是序列化的一个结构体,但是反序列化的机器上假如对应的描述文件比较旧,多了一个不用的field或者少一个新加的field,反序列化还能成功吗(去掉不关心的field)?
作者: xhl    时间: 2009-11-07 14:22
请问lz

这个库可以支持数组或则c++stl容器类型吗, 结构嵌套, 容器嵌套, 结构容器嵌套等复杂类型, 都支持吗?
作者: iunknown    时间: 2009-11-07 16:30
原帖由 emacsnw 于 2009-11-7 13:17 发表


大概看了一下代码。有个疑问。
假如用你的代码来实现RPC。传入的是序列化的一个结构体,但是反序列化的机器上假如对应的描述文件比较旧,多了一个不用的field或者少一个新加的field,反序列化还能成功吗( ...


这个问题主要和反序列化的时候,以什么为依据有关。
一个是以数据包为依据,数据包里面有什么数据,就一定要在 struct 中找到对应的 field;
一个是以struct为依据,struct 有什么字段,就从数据包中找对应的数据。

spdatapickle 采用的是后面这种方法,以 struct 为依据。

因此对于反序列化的时候,struct少一个字段,数据包中多一个字段的情况,
由于是以 struct 为依据,因此数据包中多出来的数据自动被忽略。

对于 struct 多一个字段,数据包少一个字段的情况,如果这个字段被设置为是必须的,那么反序列化就会报错。
如果这个字段不是必须的,就不会报错,字段默认是被 memset 为 0 值的。

在 field 元素中,加上 required="0" ,表示字段不是必须的。


  1.         <struct name="Email">
  2.                 <field id="1" name="Type"    type="char" arraysize="10" />
  3.                 <field id="2" name="Address" type="*char" />
  4.                 <field id="3" name="Nickname" type="*char" required="0" />
  5.         </struct>
复制代码


这个 required 的功能,就是为了接口升级而设计的。
如果不要求 spdatapickle 做严格的校验,可以把所有字段设置为 非必须的,然后由应用程序自行做校验。
如果要求 spdatapickle 做严格的校验,那么可以在升级过程中,把字段设置为非必须,在全部程序更新了之后,再把字段设置为必须的。

[ 本帖最后由 iunknown 于 2009-11-7 16:34 编辑 ]
作者: emacsnw    时间: 2009-11-07 16:39
原帖由 iunknown 于 2009-11-7 00:30 发表


这个问题主要和反序列化的时候,以什么为依据有关。
一个是以数据包为依据,数据包里面有什么数据,就一定要在 struct 中找到对应的 field;
一个是以struct为依据,struct 有什么字段,就从数据包中找对 ...


谢谢解释。我对protocol buffer这部分比较感兴趣。
简单看了一下你的解码代码,好像解码的时候没有对不认识的field进行处理,直接丢弃了?
这样的话,wire过来的bytes你如果用了一个比如是旧版本的解码器,那么数据里有几个fields不认识,忽略,使用的时候没问题。
如果你再把刚解码得到的结构体wire出去,别人受到的就不是原来的。
google protocol buffer是通过unknown_field_set来存储这些fields,这样wire回去的时候可以附上,不会损失信息。
这样是不是比较好一点?
作者: iunknown    时间: 2009-11-07 16:39
原帖由 xhl 于 2009-11-7 14:22 发表
请问lz

这个库可以支持数组或则c++stl容器类型吗, 结构嵌套, 容器嵌套, 结构容器嵌套等复杂类型, 都支持吗?


这个库只支持纯 C 的struct ,支持 struct 嵌套,支持数组。
不支持 C++ 的类,不支持 stl 容器。

要支持 C++ 的类,或者 stl 容器,可以看看 google 的 protobuf 。
spdatapickle 可以认为是 google 的 protobuf 的一个轻量版。
在我看来,google 的 protobuf 功能强大,但是也比较庞大,不够轻量。
作者: iunknown    时间: 2009-11-07 16:48
原帖由 emacsnw 于 2009-11-7 16:39 发表


简单看了一下你的解码代码,好像解码的时候没有对不认识的field进行处理,直接丢弃了?
这样的话,wire过来的bytes你如果用了一个比如是旧版本的解码器,那么数据里有几个fields不认识,忽略,使用的时候没问题。
如果你再把刚解码得到的结构体wire出去,别人受到的就不是原来的。
google protocol buffer是通过unknown_field_set来存储这些fields,这样wire回去的时候可以附上,不会损失信息。
这样是不是比较好一点?


受教,多谢指点。google 的 protobuf 没有仔细看,原来还有这样的机制。有这样的功能的确非常灵活。

猜想这个功能的作用是这样的:
接受一个包,把包解码为结构体,对结构体部分的字段做修改,然后重新编码,再发送出去。
这个功能可以用于 proxy 的场合。

这个功能不错,以后如果有需要,可以考虑加上去。
作者: xphh2008    时间: 2014-11-06 22:38
那么多年过去了,不知道楼主还在么嘿嘿

最近因为项目需求,我也需要一个类似protobuf的东西。但是因为协议是我们自己的,所以没法直接用protobuf,于是就自己写了。在搜索资料的过程中看到了这篇帖子。

我觉得把整个类似protobuf的东西开源出来可能意义不大,别人直接选protobuf或者像我一样有自定义的需求,因此我觉得比较有用的是给C结构体加反射以及实现与Json互转的这部分代码。所以我把这部分代码封装了一下,开源在github上了,叫cobj,有兴趣的朋友也可以看看:https://github.com/xphh/cobj

通过cobj的规则生成的object目前支持:

* int(整型)
* CSTR(一种自定义的常量字符串,你可以看作是Java的String,不过得记得要自己释放内存。)
* BOOL(从int直接typedef的,但是转成Json是true/false)
* 可以嵌套子结构体
* 支持int、CSTR、结构体的list(相当于支持泛型),实现为ArrayList


作者: yulihua49    时间: 2014-11-07 15:42
本帖最后由 yulihua49 于 2014-11-07 15:43 编辑
xphh2008 发表于 2014-11-06 22:38
那么多年过去了,不知道楼主还在么嘿嘿

最近因为项目需求,我也需要一个类似protobuf的东西。但是因 ...

尝试值得鼓励。
问题:
不是普通的原生态的结构。
每一个结构都要做一个元数据生成。
我的做法:
1.使用原生态的结构。
2.直接使用生成好的模板,不需要再走一遍生成。但是有一个隐式的模板初始化。

模板生成器是外置的,生成好的文件被应用程序include即可。
作者: cobras    时间: 2014-11-07 16:09
我觉得csv不错。适合传统的SQL数据库。json适合NOSQL数据库。都不错。
作者: cobras    时间: 2014-11-07 16:10
我写了一个轻量的SQL数据库服务器就是使用CSV传输数据。
作者: cobras    时间: 2014-11-07 16:11
CSV数据生成、解析就是几十行的代码。相当轻量。
作者: yulihua49    时间: 2014-11-07 16:26
本帖最后由 yulihua49 于 2014-11-07 16:45 编辑
cobras 发表于 2014-11-07 16:09
我觉得csv不错。适合传统的SQL数据库。json适合NOSQL数据库。都不错。

csv不如用分隔符的字符串,那个引号转意规则处理起来开销很大的。
json做关系数据库也很好,带着列名,解析很方便。
csv解析也就十几行,但是解析开销一点不比json少。
json的解析就一行,至于里边是几百行或几千行,跟我没关系。

JSON_OBJECT json=json_tokener_parse(rqst);
int ret;
DAU dau;
      ret=DAU_init(&dau,SQL_Connect,tabname,NULL,NULL);//dau特化成数据库表tablename
char stmt[10240];//生成语句的空间

然后反序列化:

DAU_fromJSON(&dau,json,NULL);//json按列名装载到dau里边的Record
*stmt=0;
ret=DAU_insert(&dau,stmt);//插入到数据库
......
commit;

完了,就这么简单。
DAU_free(&dau);
json_object_put(json);

DAU_init时,用tabname的数据字典生成模板和数据结构->dau。
后来的所有操作都依靠模板。

作者: cobras    时间: 2014-11-07 16:45
josn也有字符串对象。也需要引号ESC。相比较,CSV的引号转义更简单。另外的说的代码量是从0写的代码量。不是调用什么库的。
因为csv就是为数据库而生的。一行一条记录。一节一个字段。所以CSV适用于SQL,而且冗余代码少。控制代码就只有',','"'和'\n'三种。而json就多了去了。
CSV而且是迭代的。而json是递归定义的。
作者: yulihua49    时间: 2014-11-07 16:47
本帖最后由 yulihua49 于 2014-11-07 16:49 编辑
cobras 发表于 2014-11-07 16:45
josn也有字符串对象。也需要引号ESC。相比较,CSV的引号转义更简单。另外的说的代码量是从0写的代码量。不是 ...

上边说了二者解析开销差不多。json更方便些。数据量json大一些,但是,在我们的中间件里,传输是压缩的,压缩后各种格式大小差不多。
XML的解析明显要慢。
有轮子何必自己造。csv也有解析器,不过得自己找。
作者: cobras    时间: 2014-11-07 16:49
递归定义有个缺点,就是需要将整个数据缓存才通解析。而迭代定义的就没有这个问题,完全是流式的,走到哪黑就在哪歇。
作者: cobras    时间: 2014-11-07 16:50
这两种我都自己写了一套解析库。所以比较了解。还有xml也是递归定义的。
作者: yulihua49    时间: 2014-11-07 16:51
cobras 发表于 2014-11-07 16:49
递归定义有个缺点,就是需要将整个数据缓存才通解析。而迭代定义的就没有这个问题,完全是流式的,走到哪黑 ...

这不是问题。通信过来的本来就是整个的数据包。
作者: cobras    时间: 2014-11-07 16:59
csv还有一个优点就是直观。直接存成文件可以用excel打开来看和修改。
作者: cobras    时间: 2014-11-07 17:00
可以说。如果不是存储的复杂结构数据。只是存储的二维表数据。用csv就是不二之选。
作者: yulihua49    时间: 2014-11-07 20:53
本帖最后由 yulihua49 于 2014-11-07 20:54 编辑
cobras 发表于 2014-11-07 17:00
可以说。如果不是存储的复杂结构数据。只是存储的二维表数据。用csv就是不二之选。

我宁可用分隔符的字符串,与csv不同的是,不需要引号转义。
SYBASE的bcp格式就不错。
作者: xphh2008    时间: 2014-11-07 21:25
yulihua49 发表于 2014-11-07 15:42
尝试值得鼓励。
问题:
不是普通的原生态的结构。


感谢回复。

在我的项目中是通过外部工具根据协议的元描述文件自动生成结构体和metainfo的。

只不过我觉得这部分代码意义不大,所以只开源了目前这部分。我觉得这部分才是核心,别人可以自己实现自动生成结构体和metainfo的部分。

作者: xphh2008    时间: 2014-11-07 21:34
yulihua49 发表于 2009-10-10 16:05
我没有采取XML或JSON定义模板,主要是感觉在一个大型事务系统里,要附带一大堆XML文件挺累赘的,何况这些文件在运行时环境里,万一被改动,程序就死掉不明不白。
我的模板是在编译环境里,运行时看不见。所以安全一些。


XML或Json定义模板本身是没有任何问题的。模板用于生成代码,代码编译后执行。而不是在运行时再用模板生成对象。

我的项目中使用的就是Json模板,然后通过模板生成.h和.c文件,与业务系统编译后执行。
作者: yulihua49    时间: 2014-11-08 19:46
xphh2008 发表于 2014-11-07 21:34
XML或Json定义模板本身是没有任何问题的。模板用于生成代码,代码编译后执行。而不是在运行时再用模板生 ...

异曲同工。思路都差不多。
我的meta文件,也考虑过使用JSON格式。思考再三,觉得手写这种文件繁琐又易错,还是用简洁格式吧。
作者: xphh2008    时间: 2014-11-08 20:41
yulihua49 发表于 2014-11-08 19:46
异曲同工。思路都差不多。
我的meta文件,也考虑过使用JSON格式。思考再三,觉得手写这种文件繁琐又易错 ...


这个同意,手写的话,我最讨厌的就是json,一不直观,二还要有无数的引号,xml都比它好。

不过我这里用json的原因是,我项目中的协议体就是json格式,我干脆就让定义协议的元描述模板和协议本身一致了,这反而倒直观了点。

我是这样定义的,比方协议是这样:
{
    "xxx": 1,
    "yyy": "haha"
}

模板就定义为:
{
    "xxx":"[int]这个字段的说明",
    "yyy": "这个字段的说明"
}

这样还蛮取巧的呵呵。






欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2