I'm trying to convert a shapefile containing N single point shapes to a .gdb using the FileGDBAPI
for C++
from Esri.
The structure of the shapefile is:
x | y | date1 | date2 | date3 | ....
---------------------------------------------------------------------
0 | 0 | 1 | 2 | 3 | ....
1 | 0 | 2 | 1 | 0 | ....
and so on where there could be an unknown number N of dates and Z of different points
Right now all I'm doing is creating a new .gdb
file, creating a table with these fields and populating it with the same data as the shapefile.
This all works. The problem is that it's awfully slow, to convert a shapefile
with 60k points it takes almost 20 minutes.
Is there something obvious I'm missing or that I could refactor to speed up the process a bit? Right now I'm opening the .shp
, reading the fields in the .dbf
, creating a table with those fields, populating it with the various entries in the .dbf
and closing the table and the .gdb
Here is pretty much my code (error checking removed to save space but it's in the real program). Where there are comments I can't write the complete implementation but it does what it says in the comments and it's correct and optimized.
std::vector<shapes> shape_list; //Contains the shape points
FileGDBAPI::Geodatabase geodatabase;
error = CreateGeodatabase(L"./test.gdb"), geodatabase);
FileGDBAPI::SpatialReference spatialReference;
spatialReference.SetSpatialReferenceText(prj_string);
error = geodatabase.CreateFeatureDataset(L"\\Spatial_Reference", spatialReference);
std::vector<FileGDBAPI::FieldDef> field_defs;
for (int i = 0; i < dbf_field_number; ++i){
std::string dbf_field_name = field_name(i); // this gives me the dbf field name at position i
FileGDBAPI::FieldDef current_dbf_field;
current_dbf_field.SetName(dbf_field_name);
current_dbf_field.SetType(FileGDBAPI::fieldTypeDouble);
current_dbf_field.SetIsNullable(true);
current_dbf_field.SetAlias(dbf_field_name);
current_dbf_field.SetGeometryDef(geometryDef);
field_defs.push_back(current_dbf_field);
}
FileGDBAPI::Table table;
error = geodatabase.CreateTable(L"\\Data", field_defs, L"DEFAULTS", table);
for (int i = 0; i < shape_number; ++i){
FileGDBAPI::Row row;
table.CreateRowObject(row);
FileGDBAPI::PointShapeBuffer row_point;
row_point.Setup(FileGDBAPI::shapePoint);
FileGDBAPI::Point* point;
row_point.GetPoint(point);
point->x = shape_list[i]->getX();
point->y = shape_list[i]->getY();
row->SetGeometry(dbf_row_point);
for (int j = 0; j < dbf_field_number; ++j){
std::string dbf_field_name = field_name(j);
double dbf_value = field_value(i, dbf_field_name);
error = row->SetDouble(dbf_field_name, dbf_value);
}
error = table.Insert(row);
}
error = geodatabase.CompactDatabase();
error = CloseGeodatabase(geodatabase);
table.SetWriteLock()
andtable.FreeWriteLock()
which means a lock needs to be obtained for each row. I also question the need for aCompactDatabase
without any random access edits.CompactDatabase
is needed either. All I'm basing the code is the (in my opinion severely lacking)FilaGDBAPI
documentation that just states: Compact the geodatabase. Recomended after bulk updates . In my view adding a whole table with many fields constitutes as "bulk update"