前几天用2008编写了一个文件的读取过程。文件格式是S-57标准的海图数据。借用了网上现成的Parse57中的文件格式分解读取模块。然后将内容读取后记录到自己的SENC数据结构中。代码并不是很麻烦,关键是,常常屏幕中同时需要显示几幅海图,才能将屏幕填满;而且除了读取SENC海图数据外,还需要进行海图要素的显示,以及海图上层功能的显示。因此,数据处理的速度是个很重要的问题。如果速度慢,那么功能再强大,也是无法接受的。
将S-57数据解析后记录到内存的SENC数据结构的部分,在2008的debug下需要9秒,不过这个到不重要,因为海图系统运行的时候,只是从SENC中读取数据,不会直接读取S-57数据文件。形成的SENC数据,我测试了一个S-57文件大小为3.6M的形成的SENC数据,大约需要650毫秒,这还是我反复简化的结果,其中去掉了CString的使用,都是用指针和内存拷贝函数来实现文件的读取,而且用了内存映射文件。这样做,大大损失了我的数据结构的灵活性和封装性,丢失了对S-57数据协议中一部分协议的支持,而且扩展性也降低了,万一以后S-57数据的某个我目前忽略的项突然起作用了,那么可能会产生很大的影响。不过没办法,如果不这么做,那么连现在的系统都无从谈起。可650毫秒显然还是难以接受的结果。
那么, 我又在release下编译运行,经过测试,速度也在400毫秒左右,虽然有所提高,但如果需要同时读取三幅海图,那么就需要1秒左右,这个效率还是很困难。
踌躇之间,我把该模块转到VC6下运行。这个过程,我可以说是没有调整任何代码,因为模块已经封装好,外部调用函数也是一致的。测试发现,将S-57数据读取到内存SENC数据结构中,只需要4.5秒(debug下),SENC文件的读取速度与2008倒是差不多,600毫秒左右。我又用release编译运行,结果SENC文件的读取速度只需要200毫秒左右。这个速度就好多了。
为什么差距这么大呢?哪位有经验不吝赐教啊。如何才能提高2008下的速度呢?
以下是部分代码,还请大家给点建议:
HANDLE hMapObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapObject == NULL)
{
CloseHandle(hFile);
AfxMessageBox("内存映射文件创建失败。");
return FALSE;
}
//得到文件起始指针
LPVOID pBase = MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0);
BYTE *pBuf = (BYTE*)pBase;
//////////////
//DSID
m_pS57DSID = new CS57DSID;
m_pS57DSID->LoadSENC(pBuf,nVer);
//DSSI
m_pS57DSSI = new CS57DSSI;
m_pS57DSSI->LoadSENC(pBuf,nVer);
//DSPM
m_pS57DSPM = new CS57DSPM;
m_pS57DSPM->LoadSENC(pBuf,nVer);
//读取特征记录
BYTE chField[4];
memcpy(chField,pBuf,4);
pBuf += 4;
while(memcmp(chField,"DLLS",4) != 0)
{
if(memcmp(chField,"SOBJ",4) == 0)
{
long nSize = *((long*)pBuf);
pBuf += 4;
//
int nIdx = 0;
while(nIdx < nSize)
{
CS57Spatial *pS57Spatial = new CS57Spatial;
pS57Spatial->LoadSENC(pBuf,nVer);
if(pS57Spatial->m_S57VRID.RCNM == 110)
m_mapS57SpatialVI.SetAt(pS57Spatial->m_S57VRID.RCID,pS57Spatial);
else if(pS57Spatial->m_S57VRID.RCNM == 120)
m_mapS57SpatialVC.SetAt(pS57Spatial->m_S57VRID.RCID,pS57Spatial);
else if(pS57Spatial->m_S57VRID.RCNM == 130)
m_mapS57SpatialVE.SetAt(pS57Spatial->m_S57VRID.RCID,pS57Spatial);
nIdx++;
}
}
......
===================================================
//特征对象从SENC中读取其数据
void CS57Spatial::LoadSENC(BYTE *&pBuf,int nVer)
{
int i=0;
//VRID
LoadBYTE(m_S57VRID.RCNM,pBuf);
LoadLong(m_S57VRID.RCID,pBuf);
LoadShort(m_S57VRID.RVER,pBuf);
LoadBYTE(m_S57VRID.RUIN,pBuf);
//ATTV
BYTE nATTVSize;
LoadBYTE(nATTVSize,pBuf);
//
for(i=0; i<nATTVSize; i++)
{
S57_ATTR S57ATTV;
LoadShort(S57ATTV.ATTL,pBuf);
LoadBYTE(S57ATTV.nATVL,pBuf);
if(S57ATTV.nATVL > 0)
{
S57ATTV.pATVL = new BYTE[S57ATTV.nATVL];
LoadBYTEs(S57ATTV.pATVL,S57ATTV.nATVL,pBuf);
}
m_arS57ATTV.Add(S57ATTV);
}
......
===================================================
//以下按数据类型从文件中读取数据
//这些函数即使不封装,直接在上一个函数中写语句,效率也没有什么提高
void CS57DataStu::LoadBYTE(BYTE &nVal,BYTE *&pBuf)
{
nVal = *pBuf;
pBuf++;
}
void CS57DataStu::LoadShort(short &nVal,BYTE *&pBuf)
{
nVal = *((short*)pBuf);
pBuf += 2;
}
void CS57DataStu::LoadLong(long &nVal,BYTE *&pBuf)
{
nVal = *((long*)pBuf);
pBuf += 4;
}
void CS57DataStu::LoadBYTEs(BYTE *pVal,BYTE nLen,BYTE *&pBuf)
{
memcpy(pVal,pBuf,nLen);
pBuf += nLen;
}