存储外部数据
author:visualsan 2014.2 上海
1.简介
利用外部数据存储外部接口,可以在模型文件里面尺寸用户自定义数据。在模型保存时数据自动存储,在模型载入时数据自动载入。外部数据的管理完全依赖于TK函数,CROE默认情况下忽略外部数据的存在。
外部数据是由class和slot来管理的,一般情况下一个模型只需要一个class,而且每个模型的class名称必须唯一。每个class里面有一系列的slot列表,每个列表由名称或者id来表示,里面有一个数据结构用来存储数据,其类型为:int、double、wide string和stream。Stream结构里面存储的是数据流,最大长度为512kb,可以用来存储压缩数据或者数据结构。对于不同的操作系统,除了stream数据类型外,其他数据的从保存和载入都一致。
两个数据结构:ProExtdataClass和ProExtdataSlot,分别原来定义class和solt。其中solt可以通过名称或者id来定义,在创建solt时将名称为NULL时即可自动获取一个id。Class和solt的名称长度相加不能超过PRO_NAME_SIZE。Solt名称不能以数字开头。
2.C++封装
主要有三个类:Proplus_ext_solt、Proplus_ext_class和Proplus_ext_manager,作用分别为具体数据、类以及管理数据。
Proplus_ext_solt:具体数据类,封装了各种数据类型,其由CLASS创建。PTK支持四种数据double、int、string和void*。其中void*是二进制数据,可以存储长度小于512kb的数据。Proplus_ext_solt除了支持上面四种数据外,还支持大于512kb的数据。几种数据都是存储为stream格式。
设置数据的函数有:
其中info_msg是一个长度为20个字符的数据段,可以用来存自定义信息,在class里面有一个根据info_msg来查找的函数。
其它函数:
其中GetFileName是获取在SetValue_void_huge里面设置的文件名称,当保存的的数据是一个文件时,这个函数特别有用。
Proplus_ext_class:用来管理class,对于每个mdl一个class就够用了,每个class里面有若干solts,每个solt由Proplus_ext_solt管理。函数Proplus_ext_class 在析构后不会将proe内存中的solt删除,除非调用DeleteSolt或DeleteAllSolts。AddSolt函数用来添加一个新的solt。
Proplus_ext_manager:用来管理一个MDL的所有数据类。主要函数有:
3.例子
写入数据 ProMdl mdl; ProMdlCurrentGet(&mdl); ProExtdataInit(mdl);
Proplus_ext_manager cm(mdl); Proplus_ext_class &cl=*cm.ClassVector()[0];
//添加一个double数据 Proplus_ext_solt*ptr=cl.AddSolt(); ptr->SetValue_double(12.3,"---val_double");
//添加int数据 ptr=cl.AddSolt(); ptr->SetValue_int(23,"---val_int");
//添加string数据 ptr=cl.AddSolt(); ptr->SetValue_string("hello man","---val_string"); /写入二进制数据 struct st { char c[100]; int len; double d; ProName name; }; st c; strcpy(c.c,"string value"); c.len=123; c.d=3.45; ProStringToWstring(c.name,"this is wstring"); ptr=cl.AddSolt(); ptr->SetValue_void(&c,sizeof(st),"--void");
ProMdlSave(mdl);
写入文件:写入7个文件,文件大小从从1K到几十M。 ProMdl mdl; ProMdlCurrentGet(&mdl); ProExtdataInit(mdl); Proplus_ext_manager cm(mdl); Proplus_ext_class &cl=*cm.ClassVector()[0]; CString ds="E:\temp\"; //文件名称 char* names[]={ "《中国航空材料手册》第卷.结构钢.不锈钢.pdf", "[神经网络设计].(美国)Hagan.清晰版.pdf", "[讨论]复合材料金属层压板的建模.pdf", "x.exe","x.pdf","图片.rar","MSchart应用.zip" }; for (int i=0;i<7;++i) { CFile f; if(!f.Open(ds+names[i],CFile::modeRead)) continue; void*s=malloc( f.GetLength() ); f.Read(s,f.GetLength()); Proplus_ext_solt*ptr=cl.AddSolt(); ptr->SetValue_void_huge(s,f.GetLength(),names[i]); f.Close(); free(s); } ProMdlSave(mdl);
读取数据: ProMdl mdl; ProMdlCurrentGet(&mdl); Proplus_ext_manager cm(mdl); Proplus_ext_class &cl=*cm.ClassVector()[0]; DBG("solts list"); for (int i=0;i<cl.SoltsVector().size();++i) { Proplus_ext_solt*ptr=cl.SoltsVector()[i]; DBG_INT_(ptr->GetDataType()); DBG_INT_(ptr->GetDataLen()); DBG(ptr->GetSoltName()); DBG_INT_(ptr->GetID()); DBG(ptr->GetInfoMsg()); if(ptr->GetDataType()==1) { DBG("int"); int x=*(int*)ptr->GetValue(); DBG_INT(x); } if(ptr->GetDataType()==2) { DBG("double"); double x=*(double*)ptr->GetValue(); DBG_DOU_(x); } if(ptr->GetDataType()==3) { DBG("string"); char* x=(char*)ptr->GetValue(); int len=strlen(x); DBG_INT_(len); DBG(x); } if(ptr->GetDataType()==4) { DBG("void*"); DBG(ptr->GetInfoMsg()); struct st { char c[100]; int len; double d; ProName name; }; st*c=(st*)ptr->GetValue(); DBG(c->c); DBG_INT_(c->len); DBG_DOU_(c->d); char buf[200]; ProWstringToString(buf,c->name); DBG(buf); } } }
读取数据并且另存为文件: void ext_test::test_read_huge_data() { ProMdl mdl; ProMdlCurrentGet(&mdl); ProExtdataInit(mdl); Proplus_ext_manager cm(mdl); Proplus_ext_class &cl=*cm.ClassVector()[0]; CString ds="E:\temp\ds\"; int n=cl.SoltsVector().size(); for (int i=0;i<n;i++) { Proplus_ext_solt*ptr=cl.SoltsVector()[i]; if(!ptr->GetHugeValue()) continue; CString ps=ds+ptr->GetFileName(); DBG(ps); FILE*f=fopen(ps,"wb"); fwrite(ptr->GetHugeValue(),1,ptr->GetHugeDataLen(),f); fclose(f); }
4.源代码
.h文件
#pragma once #include "TKInclude.h" #include <vector> #define VOID_INFO_MSG_LEN 20 #define HUGE_DATA_SIZE 520000 #define HUGE_DATA_HEAD_TAG "HUGE_DATA_HEAD" #define HUGE_DATA_BODY_TAG "HUGE_DATA_BODY" class Proplus_ext_class; class Proplus_ext_manager; class Proplus_ext_solt { friend class Proplus_ext_class; protected: Proplus_ext_solt(ProExtdataClass*,int solt_id,Proplus_ext_class*);//init solt Proplus_ext_solt(ProExtdataClass*,Proplus_ext_class*);//create solt public: virtual ~Proplus_ext_solt(void); int GetID(); CString GetSoltName(); //data_type //1 int //2 double //3 char* //4 void* //5 huge_data int GetDataType(); bool GetStatus(); CString GetStatusMsg(); void*SetValue_int(int ,char*info_msg=NULL); void*SetValue_double(double,char*info_msg=NULL); void*SetValue_string(char*,char*info_msg=NULL ); void*SetValue_void(void*pdata ,int len/*max 512KB*/,char*info_msg=NULL/*max length 20*/); void*SetValue_void_huge(void*phuge_data ,long len,char*file_name=NULL, char*info_msg=NULL/*max length 20*/); void*GetValue();//if huge data,return the head void*GetHugeValue();//only for huge data CString GetInfoMsg();//only for void* data //如果大数据是一个文件,那么可以保存文件名称 CString GetFileName();//only for huge data int GetDataLen();//if huge data,return the len of head long GetHugeDataLen(); private: bool m_status; CString m_msg; CString m_info_msg; void*m_data_format; int m_len_of_data; int m_data_size; int m_data_type; ProExtdataSlot m_solt; ProExtdataClass*m_pProExtdataClass; Proplus_ext_class*m_pProplus_ext_class; //将数据格式化,数据前面加一类型表示符,长度为sizeof(int) //data_type //1 int //2 double //3 char* //4 void* void *FormatData(int data_type,int data_size,void *ptr,int*plen,char*info_msg=NULL); //将数据前的类型长度去除,长度plen为数据长度减去sizeof(int) void *UnFormatData(int data_size,void *ptr,int*plen); // bool WriteSoltData(ProExtdataSlot&st,void*ptr,int len); //从PROE中删除,只供class调用 bool RemoveFromProe(); //HUGE_DATA_OPERATOR struct h_data_head { long _size_of_data; int _n_of_ids; char _file_name[MAX_PATH+1];//if is a file } m_huge_head; //将数据分隔,index 1 based void *m_phuge_data; long m_len_of_huge_data; void*h_sep_data(void*,int len,int &sep_len,int index); void h_clear_huge_data(); int h_body_id(int index);//0 based }; class Proplus_ext_class { friend class Proplus_ext_manager; friend class Proplus_ext_solt; public: ~Proplus_ext_class(); //根据信息查找 std::vector<Proplus_ext_solt*> FindSolts(char*info_msg); Proplus_ext_solt* FindSolts_first(char*info_msg); std::vector<Proplus_ext_solt*>& SoltsVector(); CString GetClassName(); //add and delete solts,also delete from proe Proplus_ext_solt*AddSolt(); bool DeleteSolt(int id); void DeleteAllSolts(); ProExtdataClass&GetClass(); protected: Proplus_ext_class(ProMdl mdl,char*class_name=NULL); private: ProMdl m_mdl; CString m_class_name; ProExtdataClass m_class; bool m_status; CString m_msg; //solt vector std::vector<Proplus_ext_solt*> m_Proplus_ext_solt_vector; std::vector<Proplus_ext_solt*> m_Proplus_ext_solt_body_vector; //初始化 bool InitSolts(); // void FreeVector(); //从PROE中删除,会删除类极其数据,只供manager调用 bool RemoveFromProe(); //读取大数据 void h_read_data(); bool h_read_solt(Proplus_ext_solt*); void h_del_body(int id); }; class Proplus_ext_manager { public: Proplus_ext_manager(ProMdl mdl); ~Proplus_ext_manager(); std::vector<Proplus_ext_class*>&ClassVector(); //保存模型 void SaveMdl(); //从内存中删除,没有保存的数据将丢失 void Erase(); //add and delete class,also delete from proe Proplus_ext_class*AddClass(char *class_name); bool DeleteClass(char *class_name); void DeleteAllClasses(); ProMdl GetMdl(); private: ProMdl m_mdl; std::vector<Proplus_ext_class*> m_class_vector; CString m_msg; bool m_status; void Init(); void FreeVector(); }; struct ext_test { static void test_new_class_solt(); static void test_read_class_solt(); static void test_write_huge_data(); static void test_read_huge_data(); static void test_del_huge_data(); };
.cpp文件
#include "StdAfx.h" #include "Proplus_ext_solt.h" #include "TKInclude.h" #define DBG OutputDebugString #define DBG_INT(x) {CString str;str.Format("%d",x);DBG(str);} #define DBG_INT_(x) {CString str;str.Format("%s=%d",#x,x);DBG(str);} #define DBG_DOU_(x) {CString str;str.Format("%s=%f",#x,x);DBG(str);} #define DBG_INT2(x,y) {CString str;str.Format("%s=%d",x,y);DBG(str);} #define ER(e) if(er==e) return #e; #define MAX_BUF_LEN 524288 CString GetErrorStatus(ProExtdataErr er) { ER( PROEXTDATA_TK_NO_ERROR ); ER( PROEXTDATA_TK_INVALID_OBJ_OR_CLASS ); ER( PROEXTDATA_TK_CLASS_OR_SLOT_EXISTS ); ER( PROEXTDATA_TK_NAMES_TOO_LONG ); ER( PROEXTDATA_TK_SLOT_NOT_FOUND ); ER( PROEXTDATA_TK_BAD_KEY_BY_FLAG ); ER( PROEXTDATA_TK_INVALID_OBJ_TYPE ); ER( PROEXTDATA_TK_EMPTY_SLOT ); ER( PROEXTDATA_TK_BAD_DATA_ARGS ); ER( PROEXTDATA_TK_STREAM_TOO_LARGE ); ER( PROEXTDATA_TK_INVALID_SLOT_NAME ); ER( PROEXTDATA_TK_ERROR ); ER( PROEXTDATA_TK_MAX_SLOTS_IN_MODEL ); return "unknow"; } Proplus_ext_solt::Proplus_ext_solt(ProExtdataClass*p,int solt_id,Proplus_ext_class*pclass) { DBG("Proplus_ext_solt()"); DBG_INT_(solt_id); char buf[200]; CString str; m_pProplus_ext_class=pclass; m_len_of_huge_data = 0; m_phuge_data = 0; m_data_format=0; m_len_of_data = 0; m_pProExtdataClass = p; m_solt.p_class = m_pProExtdataClass; m_solt.slot_id = solt_id; str.Format("%d",solt_id); strcpy(buf,str); ProStringToWstring(m_solt.slot_name,buf); int data_type; void*ptr=0; ProExtdataErr er= ProExtdataSlotRead(&m_solt,KEY_BY_ID,&data_type,&m_data_size, &ptr); m_status= er==PROEXTDATA_TK_NO_ERROR; m_msg=GetErrorStatus(er); DBG(m_msg); if( ptr ) { DBG("-------------------FormatData--------------------"); m_data_type = *(int*)ptr; #if 0 m_data_format= FormatData(m_data_type,m_data_size-sizeof(int), (char*)ptr+sizeof(int),&m_data_size); #endif m_data_format=malloc(m_data_size); memcpy(m_data_format,ptr,m_data_size); CString str=GetInfoMsg(); if(str==HUGE_DATA_HEAD_TAG) { m_huge_head = *(h_data_head*)GetValue(); } m_status= er==PROEXTDATA_TK_NO_ERROR; m_msg=GetErrorStatus(er); DBG(m_msg); ProExtdataFree(&ptr); m_info_msg = (char*)m_data_format+sizeof(int); } } Proplus_ext_solt::Proplus_ext_solt(ProExtdataClass*p,Proplus_ext_class*pclass) { DBG("Proplus_ext_solt()"); m_pProplus_ext_class=pclass; m_phuge_data=0; m_data_format=0; m_len_of_data = 0; m_len_of_huge_data = 0; m_pProExtdataClass = p; ProExtdataErr er= ProExtdataSlotCreate(m_pProExtdataClass,NULL,&m_solt); m_status= er==PROEXTDATA_TK_NO_ERROR; m_msg=GetErrorStatus(er); } Proplus_ext_solt::~Proplus_ext_solt(void) { DBG("~Proplus_ext_solt"); if(m_data_format) { DBG("~free m_data_format"); free(m_data_format); } if(m_phuge_data) { DBG("~free m_phuge_data"); free(m_phuge_data); } } int Proplus_ext_solt::GetDataType() { return m_data_type; } bool Proplus_ext_solt::GetStatus() { return m_status; } CString Proplus_ext_solt::GetStatusMsg() { return m_msg; } //将数据格式化,数据前面加一类型表示符,长度为sizeof(int) //data_type //1 int //2 double //3 void //4 char* void *Proplus_ext_solt::FormatData(int data_type,int data_size, void *ptr,int*plen,char*info_msg) { DBG("FormatData"); DBG_INT_(data_type); DBG_INT_(data_size); if ( !m_info_msg.IsEmpty() && NULL==info_msg) { strcpy(info_msg,m_info_msg); } *plen = data_size +sizeof(int)+VOID_INFO_MSG_LEN; char*pdata=(char*)malloc( *plen ); memcpy(pdata,&data_type,sizeof(int));//type m_info_msg=info_msg; if(info_msg) { int len=strlen(info_msg); if(len>=VOID_INFO_MSG_LEN) len = VOID_INFO_MSG_LEN-1; memcpy(pdata+sizeof(int),info_msg,len+1 ); pdata[ sizeof(int)+VOID_INFO_MSG_LEN ] ='