使用GDAL/OGR操作Postgresql數據庫



GDAL(Geospatial Data AbstractionLibrary)是一個在X/MIT許可協議下的開源柵格空間數據轉換庫。它利用抽象數據模型來表達所支持的各種文件格式。它還有一系列命令行工具來進行數據轉換和處理。

本文將使用GDAL/OGR庫讀寫Postgresql數據庫中的表,代碼執行環境在ubuntu12.04

直接上代碼


#include "/usr/include/gdal/ogrsf_frmts.h"
#include "/usr/include/gdal/ogr_feature.h"
#include "/usr/include/gdal/ogr_geometry.h"
#include "/usr/include/gdal/gdal_priv.h"
	///////////////////////////////
//使用OGR讀Postgresql
///////////////////////////////
int getFeature( vector<RoadRec>& RoadList //RoadRec是自定義數據結構
 )
{
	OGRRegisterAll();
	const char* filepath =
	"PG:dbname=test host=172.0.0.1 port=5432 user=postgres password=postgres";
	const char* drivename = "PostgreSQL"; //標明是Postgresql數據庫操作
	const char* ptablename = "roadlist";//數據表名稱 table name
	OGRSFDriver* pdriver = NULL;
	OGRLayer* player = NULL;
	OGRDataSource* pDS = NULL;
    //註冊驅動,這樣ogr就知道即將打開的是什麼類型的文件
	pdriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(drivename);

	if ( pdriver == NULL ) {
		return FAILURE;
	}
    //驅動註冊完畢打開數據庫
	pDS = pdriver->Open(filepath,0);
	if ( NULL == pDS ) {
		return FAILURE;
	}
    //打開數據庫中的數據表
	player = pDS->GetLayerByName(ptablename);
	if ( NULL == player ) {
		return FAILURE;
	}
	//OGRFeature*相當於指向數據表中一條記錄的指針,根據它可以獲取每一個字段
	OGRFeature* pogrfeature = NULL;
	player->ResetReading();
	int gid = 0;


    //循環遍歷每一條記錄,這裏的遍歷是按照表中數據的存儲順序遍歷
    //並不會按照主鍵唯一值順序遍歷,這和SQL的select結果的順序不一樣
    //想要一樣應該創建索引,並將表數據按索引順序存儲
/*
CREATE INDEX roadlist_gid_idx
  ON roadlist
  USING btree
  (gid);

cluster  roadlist using roadlist_gid_idx;
*/
	while( (pogrfeature = player->GetNextFeature()) != NULL )
	{
	    gid++;
		//獲取一條記錄中的幾何屬性字段的引用
		OGRGeometry *pgeo = pogrfeature->GetGeometryRef();
		if ( NULL != pgeo )
		{
			//判斷一下是不是自己想要的類型,這裏我的數據是道路,line數據
		    if ( wkbMultiLineString == pgeo->getGeometryType() || wkbLineString == pgeo->getGeometryType() )
		    {
		        OGRGeometry* pgeometry = pgeo;
				//單獨處理一下multilinestring的情況
		        if ( wkbMultiLineString == pgeo->getGeometryType() )
		        {
		            OGRMultiLineString* pmultilinestring = (OGRMultiLineString*)pgeo;
                    if( 1 != pmultilinestring->getNumGeometries() )
                    {
                        return FAILURE;
                    }
                    pgeometry = pmultilinestring->getGeometryRef(0);
		        }
				//定義OGRLineString類型指針指向幾何數據
				//這樣就可以使用OGRLineString提供的函數接口了
                OGRLineString* pline = (OGRLineString *)pgeometry;
                int pointnum = pline->getNumPoints();
                RoadRec tmp;//自定義數據類型
				//使用OGRFeature類提供的 GetFieldAsInteger
//方法獲取每個字段的值,”link_id”,”road_name”都是字段名
				
                tmp.link_id = pogrfeature->GetFieldAsInteger("link_id");
                //tmp.src_id = pogrfeature->GetFieldAsInteger("src_id");
                tmp.road_name = pogrfeature->GetFieldAsString("road_name");
                tmp.one_way = pogrfeature->GetFieldAsInteger("one_way");
				//獲得幾何屬性的每一個點座標信息
                for ( int pointid = 0; pointid < pointnum;++pointid )
                {
                    OGRPoint point;
                    pline->getPoint(pointid,&point);
                    GEO_POINT geo_point;
                    geo_point.x = point.getX();
                    geo_point.y = point.getY();

                    tmp.vstShplist.push_back(geo_point);
                }
                RoadList.push_back(tmp);
		    }
		}
		//釋放Feature資源
        OGRFeature::DestroyFeature(pogrfeature);
        //cout<<link_id<<endl;
	}
    //釋放指向該數據庫的指針
OGRDataSource::DestroyDataSource(pDS);
	return SUCCESS;
}

///////////////////////////////
//使用OGR寫Postgresql
///////////////////////////////
int setFeature( const vector<RoadRec>& RoadList )
{
    OGRRegisterAll();
	const char* filepath =
	"PG:dbname=test host=172.0.0.1 port=5432 user=postgres password=postgres";
	const char* drivename = "PostgreSQL";
	const char* ptablename = "roadlist";
	OGRSFDriver* pdriver = NULL;
	OGRLayer* player = NULL;
	OGRDataSource* pDS = NULL;

	pdriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(drivename);
	if ( pdriver == NULL ) {
		return FAILURE;
	}

	pDS = pdriver->Open(filepath,0);
	if ( NULL == pDS ) {
		return FAILURE;
	}
    //相當於sql語句中的創建數據表,只是這裏只先指定表名稱和幾何字段屬性
    player = pDS->CreateLayer( ptablename,NULL,wkbLineString,NULL );
    if ( NULL == player )
    {
            return FAILURE;
    }
    //定義一個字段one_way
    OGRFieldDefn* pfielddefn_oneway = new OGRFieldDefn("one_way",OFTInteger);
    //在數據表中創建定義的字段
    player->CreateField(pfielddefn_oneway);
    OGRFieldDefn* pfielddefn_name = new OGRFieldDefn("road_name",OFTString);
    player->CreateField(pfielddefn_name);
    //刪除字段定義指針
    delete pfielddefn_oneway;
    delete pfielddefn_name;

    int roadnum = RoadList.size();
    //循環寫入每一條道路數據
    for ( int roadcnt = 0; roadcnt < roadnum ;++roadcnt )
    {
            const RoadRec& roadrec = RoadList.at(roadcnt);
            OGRLineString* pline = new OGRLineString;//要寫入的幾何字段

            int pointnum = roadrec.vstShplist.size();
            for ( int pointcnt = 0; pointcnt < pointnum ;++pointcnt )
            {
                    const GEO_POINT& point = roadrec.vstShplist.at(pointcnt);
                    pline->addPoint(point.x,point.y);
            }
            OGRGeometry* pgeo = (OGRGeometry*)pline;
            pgeo->setCoordinateDimension(2);//設置座標系維度
            //創建一個指向要寫入的記錄的指針
//指定要寫入的數據庫player->GetLayerDefn()
            OGRFeature* pfeature = OGRFeature::CreateFeature( player->GetLayerDefn() );
			//設置當前記錄的字段值
            pfeature->SetField("one_way",roadrec.one_way);
            pfeature->SetField("road_name",roadrec.road_name.c_str());

            if ( OGRERR_NONE != pfeature->SetGeometry( pgeo ) )
            {
                    return FAILURE;
            }
			//將記錄寫入數據表
            if ( OGRERR_NONE != player->CreateFeature( pfeature ) )
            {
                    return FAILURE;
            }

            delete pline;

            OGRFeature::DestroyFeature(pfeature);
    }

    OGRDataSource::DestroyDataSource(pDS);

	return SUCCESS;
}

int main()
{
	vector<RoadRec> roadlist;
	getFeature(roadlist);
	cout<<roadlist.size()<<endl;
    setFeature(roadlist);
	return 0;
}


編譯鏈接:g++ -o feature feature_pro.cpp -lgdal



發佈了33 篇原創文章 · 獲贊 11 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章