OGR库读写mif/tab文件lonefox使用经验小结

 ===================================

本人log中所有未注明转载的文章和blog一般为本人原创或整理加工,
原创文章版权本人(lonefox)所有;转载文章版权归原作者所有;

http://blog.csdn.net/boythl

欢迎转载,但请注明出处,保留作者和版权信息。

===================================

  

最近项目中使用GDAL/OGR库读写mif和tab文件, 经过几天的折腾,积累了点点经验,且记之.

 

1. OGRSFDriverRegistrar::Open(Path, FALSE);只能读文件

对于OGRSFDriverRegistrar::Open方法, ogr内置的mif/TAB读写库MITAB是不支持该方法的更新的,看下面的MITAB源码:

  再深入源码,你会发现,通过Open方法传给IMapInfoFile类访问文件的方式是TABRead,而非TABWrite

  也许你会说”这是OGRTABDriver的方法, 可以看看OGRMIFDriver的方法?”, 遗憾, 我们只能用 RegisterOGRTAB(); 注册mif和tab通用的驱动,RegisterOGRMIF();是一个只有定义而没有函数实现的美丽谎言, 不知道OGR库留着这个定义的目的何在。也不存在OGRMIFDriver,OGRTABDriver通吃mif和tab文件。这也是我们的第二点。

 

2.只使用RegisterOGRTAB();注册tab/MIF文件读写驱动

原因上面已经提过。单凭RegisterOGRTAB();已足够。

mif和tab文件的读取都是通过Open方法,MITAB库内部会调用SmartOpen方法区分是mif/mid后缀或是tab后缀。

 

3.写mif/tab文件的方法

OGRSFDriver *pDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(“MapInfo File”);
OGRDataSource *pDSTAB = pDriver->CreateDataSource(strTabPath);//创建一个文件,根据扩展名自动判断是创建mif文件或tab文件

lonefox的解释: MITAB库在实现CreateDataSource方法时会调用OGRTABDataSource的Create方法,而非Open方法

Create方法内部会调用IMapInfoFile类的Open方法,但区别在于访问模式参数传递的是”wb”!

而该模式将标记 m_eAccessMode = TABWrite; 不是OGRDataSource::Open方法对应的TABRead模式;

顺带提句,IMapInfoFile内只有TABWrite和TABRead, 是不能又读又写的

 

4.读写mif/tab的方法

如果我一个文件已有部分数据,但我想打开后继续加数据,怎么办?

我采取一种曲线救国的方法解决该问题: i. 打开该文件; ii.按上面第三条的方法新建一个临时文件供写入; iii. 使用OGRDataSource类的CopyLayer方法将 i 中打开的旧数据贴进新layer,iv. 调用OGRLayer::SyncToDisk方法保存新文件;v. 删除旧文件将临时文件更名

若有大侠有更好的方法,一定要不吝指教才好!!!

 

5. mif/tab格式互转

利用OGRDataSource::CopyLayer,mif和tab格式的互转就再简单不过了。直接源码吧

tab转mif和上面代码雷同,略之。

 

6. ogr库的bug

6.1. 读取空mif文件失败的限制

如果一个mif文件是空文件(当然,文件格式是符合mif格式的,只是图层中没有feature),即mid文件尺寸为0;那么,ogr的open方法会返回NULL,意味着读取失败。

这是因为MITAB库在打开mid文件时会尝试读一行

这段代码位于int MIFFile::Open(const char *pszFname, const char *pszAccess, GBool bTestOpenNoError /*=FALSE*/ )方法内部。

有两种方法解决该问题: 1. 修改ogr库源码,先前我们是这么干的;2. 打开前向空mid文件插入一个换行符,该字符的存在能“欺骗”上文GetLine方法不返回NULL

 

6.2. 字符集的限制

ogr写出的mif/tab文件,字符集全部都是Neutral,根本不管先前的charset,鄙人驽钝,未发现修改字符集的方法,有大虾知道的话请千万要不吝指教啊!

但在IMapInfoFile类中存在一个SetCharset接口,该方法由IMapInfoFile默认实现,未被override;且该方法在MITAB库内部未被调用。

问题是OGR库未提供类似接口。

解决方法: 1. 修改ogr库,增加一个设置charset的接口。2. 抛弃OGR库,直接使用IMapInfoFile类操纵mif文件

 

6.3. 只支持少量sql查询,不支持空间查询

sql查询的相关内容可以看swq.h文件; 空间查询在OGR1.60版还未看到接口,期待。

 

7. 尽量使用GetNextFeature代替GetFeatureCount

我们看看OGRLayer::GetFeatureCount方法的实现代码

由上可以看到,大部分情况下,GetFeatureCount的参数取False时将直接得到-1;如果采用TRUE,不好意思,就是一次整图层所有feature的遍历。

很遗憾的是,MITAB库并未override该方法,也就没有更高效的算法了。

因此, 如果想判断图层是否有feature,例如sql查询的查询结果是否为空,不明确要求得到要素个数时,请先使用ResetReading再判断GetNextFeature是否为NULL,避免使用GetFeatureCount。

切记,OGR的GetFeatureCount不同于ado库的GetRecordCount。

 

    时间匆忙,lonefox上班间隙随手写就,再加就几天的使用,经验有限,错误之处恳请斧正;另,GIS同行欢迎加好友共同探讨!

转载自:https://blog.csdn.net/boythl/article/details/4819613

You may also like...