在ArcGIS Engine开发过程中,比较常用并且重要的功能就是数据转换,对于数据转换方法您是否足够清楚?ArcGIS Engine中常用的数据转换方法有哪些?各种转换方法的优缺点是什么?采用哪种方法效率更高?如果您对这些问题感兴趣,那么一定要阅读下面文章,相信一定会让您有所收获。
IFeatureDataConverter:细粒度,用于复制单个简单要素类或者要素数据集。优点:可使用QueryFilter(属性和空间均可)进行过滤,可以设置SubFields指定复制哪些字段,可以改变要素类的geometry definition以及设置configuration_keyword。除此之外,还可以在基于文件的数据源(如ShapeFile)与地理数据库之间进行复制。缺点:只能转换简单要素类和要素数据集,无法转换关系类,几何网络,拓扑等复杂对象。
IGeoDBDataTransfer(等同于ArcCatalog中对地理数据库中数据集的复制和粘贴):适用于两个地理数据库之间复制一个或多个数据集。优点:可以一次导入多个数据集,并且能转换几乎所有类型的数据,包括关系类、拓扑、几何网络等复杂对象。缺点:不能进行条件过滤,也不能在基于文件的数据源与地理数据库之间进行复制,即不能实现shapefile与FileGDB、MDB或SDE间的导入导出。
IGdbXmlExport and IGdbXmlImport:使用XML作为中间文件,适用于两个地理数据库之间复制一个或多个数据集。优点:可以在离线下使用。比如SDE往其它地理数据库中进行数据导入,在连接上SDE时生成xml文件,后面即使断开该SDE连接,也可以成功将xml(可仅包括Schema,也可以包含数据)导入到目标库中。还有一个优点是便于数据共享与传输,如果给多个人共享数据,只需拷贝该xml文件即可。
IExportOperation:复制单个数据集到另一个Workspace,是经过包装的IFeatureDataConverter。优点:可以设置QueryFilter以及SelectionSet,可以跨数据源进行转换,比如从ShapeFile到GeoDatabase,并且可以显示进度条。缺点:只能在Desktop产品下使用。
IDataset.Copy:从基于文件的数据源(例如shapefile,dbf或coverage要素类)中复制Dataset到另一个基于文件的数据源。
IWorkspaceFactory(copy或者move):复制或移动整个local geodatabase或SDE 连接文件。
IObjectLoader:往已有数据集中添加记录,仅能在Desktop产品下使用。由于本文仅讨论复制要素类的情况,该接口我们将在下一篇关于Engine中如何往已有要素类中插入数据中讨论。
当然,不要忘了还可以在程序中调用GP工具进行要素类的复制,比如FeatureClassToFeatureClass工具、FeatureClassToGeoDatabase工具、CopyFeatures工具以及Copy工具。
前面我们介绍了Engine中常用的复制要素类的几种方法及每种方法的优缺点,接下来我们就进行测试,对比一下效率。本文以将FileGDB中含有20万条记录的点要素类导入SDE中为例进行测试。
代码可参考 ArcGIS帮助
Tips:如果程序中绑定Engine,则需要初始化EngineGeoDB许可(编辑SDE数据需要该许可,当然如果绑定Desktop,也可以使用Standard或者Advanced许可),直接使用Engine许可会报下面错误。
下面我们就看测试结果吧。
1, 使用IFeatureDataConverter.ConvertFeatureClass将FileGDB中要素类导入SDE中所用时间为:3分钟16秒。为了便于对比,这里没有设置查询条件以及SubFields等。
2,使用IGeoDBTransfer.Transfer将同样数据导入SDE中所用时间为:2分42秒,比第一种方法快34秒。效率提高了17%,目前我导入的数据量仅为20万,相信如果数据量再大些,该方法的效率会更突出。
3,使用IGdbXmlExport将FileGDB中的要素类导出成xml所用时间为:1分55秒,接着使用IGdbXmlImport将生成的xml导入到SDE中所用时间为:4分27秒。两个时间加起来显然并未提高效率,但是生成一次xml,后续可以将其导入任意地理数据库中,便于传输与共享。
4,最后测试使用IExportOperation.ExportFeatureClass 方法,注意该接口只能在Desktop产品下使用,也就是程序中需要绑定Desktop并且初始化Standard或者Advanced许可。执行该方法时会自动出现进度条来显示进度。
所用时间为:3分22秒。可见该方法与IFeatureDataConverter所用时间大致相同,也就验证了前面说的“IExportOperation是包装过的IFeatureDataConverter”说法,如果您的程序中不需要使用MapControl、ToolBarControl等控件,并且需要显示进度条,那么使用这个方法最合适不过了。
其余的IDataset.Copy,IWorkspaceFactory(copy或者move)以及IObjectLoader方法无法实现将FileGDB中的要素类导出到SDE中,所以这里就不做讨论了。接下来我们在程序中调用GP工具测试一下时间。
1,调用FeatureClassToFeatureClass工具,所用时间为3分32秒。
2,调用FeatureClassToGeoDatabase工具,所用时间为3分4秒。
3,调用CopyFeatures工具,所用时间为3分25秒。
4,调用Copy工具,所用时间为2分45秒。
从执行时间上可以发现Copy工具和FeatureClassToGeoDatabase工具用时较少,为大家提供一个参考。
小结:执行相同操作所花时间的长短虽然是一个程序是否可优化的考量因素,但是最重要的是实际需求,比如IGeoDBDataTransfer虽然较IFeatureDataConverter用时短,但是如果想在复制过程中进行查询或者设置SubFields,再或者要将shapeFile导入SDE中,那么就只能使用IFeatureDataConverter了。
说了这么多,前面的东西是否又忘了呢,不要紧,文章最后将之前提到的使用AO接口导入数据的方法汇总如下:
完整代码:
using ESRI.ArcGIS.Catalog;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.GeoDatabaseDistributed;
using ESRI.ArcGIS.GeoDatabaseUI;
using ESRI.ArcGIS.Geoprocessing;
using ESRI.ArcGIS.Geoprocessor;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace convertingData
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string sdePath = @"C:\Users\Xinying\AppData\Roaming\ESRI\Desktop10.4\ArcCatalog\Connection to 192.168.220.132.sde";
string fileGDBPath = Application.StartupPath + "\\test.gdb";
string sourceFCName = "testPoint_20w";
string targetFCName = "testPoint_20w_sde";
string outputXmlFile = Application.StartupPath + "\\workspaceGDB.XML";
private void iFeatureDataConverterToolStripMenuItem_Click(object sender, EventArgs e)
{
Stopwatch myWatch = Stopwatch.StartNew();
ConvertFileGDBToSDE(fileGDBPath, sourceFCName, targetFCName);
myWatch.Stop();
string time = myWatch.Elapsed.TotalMinutes.ToString();
MessageBox.Show(time + " Minutes");
}
public void ConvertFileGDBToSDE(string fileGDBPath, string sourceFCName, string targetFCName)
{
// Create a name object for the source (fileGDB) workspace and open it.
IWorkspaceName sourceWorkspaceName = getWorkspaceName("esriDataSourcesGDB.FileGDBWorkspaceFactory", fileGDBPath);
IName sourceWorkspaceIName = (IName)sourceWorkspaceName;
IWorkspace sourceWorkspace = (IWorkspace)sourceWorkspaceIName.Open();
// Create a name object for the target (SDE) workspace and open it.
IWorkspaceName targetWorkspaceName = getWorkspaceName("esriDataSourcesGDB.SdeWorkspaceFactory", sdePath);
IName targetWorkspaceIName = (IName)targetWorkspaceName;
IWorkspace targetWorkspace = (IWorkspace)targetWorkspaceIName.Open();
// Create a name object for the source dataset.
IFeatureClassName sourceFeatureClassName = getFeatureClassName(sourceWorkspaceName, sourceFCName);
// Create a name object for the target dataset.
IFeatureClassName targetFeatureClassName = getFeatureClassName(targetWorkspaceName, targetFCName);
// Open source feature class to get field definitions.
IName sourceName = (IName)sourceFeatureClassName;
IFeatureClass sourceFeatureClass = (IFeatureClass)sourceName.Open();
// Create the objects and references necessary for field validation.
IFieldChecker fieldChecker = new FieldCheckerClass();
IFields sourceFields = sourceFeatureClass.Fields;
IFields targetFields = null;
IEnumFieldError enumFieldError = null;
// Set the required properties for the IFieldChecker interface.
fieldChecker.InputWorkspace = sourceWorkspace;
fieldChecker.ValidateWorkspace = targetWorkspace;
// Validate the fields and check for errors.
fieldChecker.Validate(sourceFields, out enumFieldError, out targetFields);
if (enumFieldError != null)
{
// Handle the errors in a way appropriate to your application.
Console.WriteLine("Errors were encountered during field validation.");
}
// Find the shape field.
String shapeFieldName = sourceFeatureClass.ShapeFieldName;
int shapeFieldIndex = sourceFeatureClass.FindField(shapeFieldName);
IField shapeField = sourceFields.get_Field(shapeFieldIndex);
// Get the geometry definition from the shape field and clone it.
IGeometryDef geometryDef = shapeField.GeometryDef;
IClone geometryDefClone = (IClone)geometryDef;
IClone targetGeometryDefClone = geometryDefClone.Clone();
IGeometryDef targetGeometryDef = (IGeometryDef)targetGeometryDefClone;
// Cast the IGeometryDef to the IGeometryDefEdit interface.
IGeometryDefEdit targetGeometryDefEdit = (IGeometryDefEdit)targetGeometryDef;
// Set the IGeometryDefEdit properties.
//targetGeometryDefEdit.GridCount_2 = 1;
//targetGeometryDefEdit.set_GridSize(0, 0.75);
// Create a query filter to only select features you want to convert
IQueryFilter queryFilter = new QueryFilterClass();
// Create the converter and run the conversion.
IFeatureDataConverter featureDataConverter = new FeatureDataConverterClass();
IEnumInvalidObject enumInvalidObject = featureDataConverter.ConvertFeatureClass
(sourceFeatureClassName, queryFilter, null, targetFeatureClassName,
targetGeometryDef, targetFields, "", 1000, 0);
// Check for errors.
IInvalidObjectInfo invalidObjectInfo = null;
enumInvalidObject.Reset();
while ((invalidObjectInfo = enumInvalidObject.Next()) != null)
{
// Handle the errors in a way appropriate to the application.
Console.WriteLine("Errors occurred for the following feature: {0}",
invalidObjectInfo.InvalidObjectID);
}
}
//"esriDataSourcesGDB.FileGDBWorkspaceFactory"
//"esriDataSourcesFile.ShapefileWorkspaceFactory"
//"esriDataSourcesGDB.SdeWorkspaceFactory"
private IWorkspaceName getWorkspaceName(string WorkspaceFactoryProgID, string PathName)
{
IWorkspaceName workspaceName = new WorkspaceNameClass
{
WorkspaceFactoryProgID = WorkspaceFactoryProgID,
PathName = PathName
};
return workspaceName;
}
private IFeatureClassName getFeatureClassName(IWorkspaceName WorkspaceName, string Name)
{
// Create a name object for the dataset.
IFeatureClassName featureClassName = new FeatureClassNameClass();
IDatasetName datasetName = (IDatasetName)featureClassName;
datasetName.Name = Name;
datasetName.WorkspaceName = WorkspaceName;
return featureClassName;
}
private void iGeoDBTransferToolStripMenuItem_Click(object sender, EventArgs e)
{
Stopwatch myWatch = Stopwatch.StartNew();
TansferFileGDBToSDE(fileGDBPath, sourceFCName);
myWatch.Stop();
string time = myWatch.Elapsed.TotalMinutes.ToString();
MessageBox.Show(time + " Minutes");
}
public void TansferFileGDBToSDE(string fileGDBPath, string sourceFCName)
{
// Create workspace name objects.
IWorkspaceName sourceWorkspaceName = getWorkspaceName("esriDataSourcesGDB.FileGDBWorkspaceFactory", fileGDBPath);
// Create a name object for the target (SDE) workspace and open it.
IWorkspaceName targetWorkspaceName = getWorkspaceName("esriDataSourcesGDB.SdeWorkspaceFactory", sdePath);
IName targetName = (IName)targetWorkspaceName;
// Create a name object for the source dataset.
IFeatureClassName sourceFeatureClassName = getFeatureClassName(sourceWorkspaceName, sourceFCName);
IName sourceName = (IName)sourceFeatureClassName;
// Create an enumerator for source datasets.
IEnumName sourceEnumName = new NamesEnumeratorClass();
IEnumNameEdit sourceEnumNameEdit = (IEnumNameEdit)sourceEnumName;
// Add the name object for the source class to the enumerator.
sourceEnumNameEdit.Add(sourceName);
// Create a GeoDBDataTransfer object and a null name mapping enumerator.
IGeoDBDataTransfer geoDBDataTransfer = new GeoDBDataTransferClass();
IEnumNameMapping enumNameMapping = null;
// Use the data transfer object to create a name mapping enumerator.
Boolean conflictsFound = geoDBDataTransfer.GenerateNameMapping(sourceEnumName,
targetName, out enumNameMapping);
enumNameMapping.Reset();
// Check for conflicts.
if (conflictsFound)
{
// Iterate through each name mapping.
INameMapping nameMapping = null;
while ((nameMapping = enumNameMapping.Next()) != null)
{
// Resolve the mapping's conflict (if there is one).
if (nameMapping.NameConflicts)
{
nameMapping.TargetName = nameMapping.GetSuggestedName(targetName);
}
// See if the mapping's children have conflicts.
IEnumNameMapping childEnumNameMapping = nameMapping.Children;
if (childEnumNameMapping != null)
{
childEnumNameMapping.Reset();
// Iterate through each child mapping.
INameMapping childNameMapping = null;
while ((childNameMapping = childEnumNameMapping.Next()) != null)
{
if (childNameMapping.NameConflicts)
{
childNameMapping.TargetName = childNameMapping.GetSuggestedName(targetName);
}
}
}
}
}
// Start the transfer.
geoDBDataTransfer.Transfer(enumNameMapping, targetName);
}
private void ExportDatasetToXML(string fileGdbPath, string sourceFCName, string outputXmlFile)
{
// Open the source geodatabase and create a name object for it.
IWorkspaceName sourceWorkspaceName = getWorkspaceName("esriDataSourcesGDB.FileGDBWorkspaceFactory", fileGdbPath);
IFeatureClassName sourceFeatureClassName = getFeatureClassName(sourceWorkspaceName, sourceFCName);
IName sourceName = (IName)sourceFeatureClassName;
// Create a new names enumerator and add the feature dataset name.
IEnumNameEdit enumNameEdit = new NamesEnumeratorClass();
enumNameEdit.Add(sourceName);
IEnumName enumName = (IEnumName)enumNameEdit;
// Create a GeoDBDataTransfer object and create a name mapping.
IGeoDBDataTransfer geoDBDataTransfer = new GeoDBDataTransferClass();
IEnumNameMapping enumNameMapping = null;
geoDBDataTransfer.GenerateNameMapping(enumName, sourceWorkspaceName as IName, out enumNameMapping);
// Create an exporter and export the dataset with binary geometry, not compressed,
// and including metadata.
IGdbXmlExport gdbXmlExport = new GdbExporterClass();
gdbXmlExport.ExportDatasets(enumNameMapping, outputXmlFile, true, false, true);
}
private void ImportXmlWorkspaceDocument(string inputXmlFile)
{
IWorkspaceName targetWorkspaceName = getWorkspaceName("esriDataSourcesGDB.SdeWorkspaceFactory", sdePath);
IName targetName = (IName)targetWorkspaceName;
IWorkspace targetWorkspace = (IWorkspace)targetName.Open();
IGdbXmlImport gdbXmlImport = new GdbImporterClass();
IEnumNameMapping enumNameMapping = null;
Boolean conflictsFound = gdbXmlImport.GenerateNameMapping(inputXmlFile, targetWorkspace, out enumNameMapping);
// Check for conflicts.
if (conflictsFound)
{
// Iterate through each name mapping.
INameMapping nameMapping = null;
enumNameMapping.Reset();
while ((nameMapping = enumNameMapping.Next()) != null)
{
// Resolve the mapping's conflict (if there is one).
if (nameMapping.NameConflicts)
{
nameMapping.TargetName = nameMapping.GetSuggestedName(targetName);
}
// See if the mapping's children have conflicts.
IEnumNameMapping childEnumNameMapping = nameMapping.Children;
if (childEnumNameMapping != null)
{
childEnumNameMapping.Reset();
// Iterate through each child mapping.
INameMapping childNameMapping = null;
while ((childNameMapping = childEnumNameMapping.Next()) != null)
{
if (childNameMapping.NameConflicts)
{
childNameMapping.TargetName =
childNameMapping.GetSuggestedName(targetName);
}
}
}
}
}
// Import the workspace document, including both schema and data.
gdbXmlImport.ImportWorkspace(inputXmlFile, enumNameMapping, targetWorkspace, false);
}
private void exportDatasetToXMLImportToolStripMenuItem_Click(object sender, EventArgs e)
{
Stopwatch myWatch = Stopwatch.StartNew();
ExportDatasetToXML(fileGDBPath, sourceFCName, outputXmlFile);
myWatch.Stop();
string time = myWatch.Elapsed.TotalMinutes.ToString();
MessageBox.Show(time + " Minutes");
Stopwatch myWatch1 = Stopwatch.StartNew();
ImportXmlWorkspaceDocument(outputXmlFile);
myWatch1.Stop();
string time1 = myWatch1.Elapsed.TotalMinutes.ToString();
MessageBox.Show(time1 + " Minutes");
}
private void iExportOperationToolStripMenuItem_Click(object sender, EventArgs e)
{
Stopwatch myWatch = Stopwatch.StartNew();
ExportOperationFileGDBToSDE(fileGDBPath, sourceFCName, targetFCName);
myWatch.Stop();
string time = myWatch.Elapsed.TotalMinutes.ToString();
MessageBox.Show(time + " Minutes");
}
public void ExportOperationFileGDBToSDE(string fileGDBPath, string sourceFCName, string targetFCName)
{
// Create a name object for the source (file GDB) workspace and open it.
IWorkspaceName sourceWorkspaceName = getWorkspaceName("esriDataSourcesGDB.FileGDBWorkspaceFactory", fileGDBPath);
IName sourceWorkspaceIName = (IName)sourceWorkspaceName;
IWorkspace sourceWorkspace = (IWorkspace)sourceWorkspaceIName.Open();
// Create a name object for the target (sde) workspace and open it.
IWorkspaceName targetWorkspaceName = getWorkspaceName("esriDataSourcesGDB.SdeWorkspaceFactory", sdePath);
// Create a name object for the source dataset.
IFeatureClassName sourceFeatureClassName = getFeatureClassName(sourceWorkspaceName, sourceFCName);
// Create a name object for the target dataset.
IFeatureClassName targetFeatureClassName = getFeatureClassName(targetWorkspaceName, targetFCName);
// Open source feature class to get field definitions.
IName sourceName = (IName)sourceFeatureClassName;
IFeatureClass sourceFeatureClass = (IFeatureClass)sourceName.Open();
// Find the shape field.
String shapeFieldName = sourceFeatureClass.ShapeFieldName;
int shapeFieldIndex = sourceFeatureClass.FindField(shapeFieldName);
IField shapeField = sourceFeatureClass.Fields.get_Field(shapeFieldIndex);
// Get the geometry definition from the shape field and clone it.
IGeometryDef geometryDef = shapeField.GeometryDef;
IClone geometryDefClone = (IClone)geometryDef;
IClone targetGeometryDefClone = geometryDefClone.Clone();
IGeometryDef targetGeometryDef = (IGeometryDef)targetGeometryDefClone;
// Cast the IGeometryDef to the IGeometryDefEdit interface.
IGeometryDefEdit targetGeometryDefEdit = (IGeometryDefEdit)targetGeometryDef;
// Set the IGeometryDefEdit properties.
//targetGeometryDefEdit.GridCount_2 = 1;
//targetGeometryDefEdit.set_GridSize(0, 0.75);
// Create a query filter to only select features you want to convert
IQueryFilter queryFilter = new QueryFilterClass();
// Create the converter and run the conversion.
IExportOperation exportOperation = new ExportOperationClass();
exportOperation.ExportFeatureClass(sourceFeatureClassName as IDatasetName, queryFilter, null, targetGeometryDef, targetFeatureClassName, 0);
}
private void ExecuteGP(IGPProcess GPProcess)
{
Geoprocessor gp = new Geoprocessor { OverwriteOutput = true };
try
{
IGeoProcessorResult2 result = gp.Execute(GPProcess, null) as IGeoProcessorResult2;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "GP Error");
}
finally
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < gp.MessageCount; i++)
sb.AppendLine(gp.GetMessage(i));
if (sb.Capacity > 0) MessageBox.Show(sb.ToString(), "GP Messages");
}
}
private void featureClassToFeatureClassToolStripMenuItem_Click(object sender, EventArgs e)
{
ESRI.ArcGIS.ConversionTools.FeatureClassToFeatureClass featureClassToFeatureClass = new ESRI.ArcGIS.ConversionTools.FeatureClassToFeatureClass();
featureClassToFeatureClass.in_features = fileGDBPath + "\\" + sourceFCName;
featureClassToFeatureClass.out_path = sdePath;
featureClassToFeatureClass.out_name = targetFCName;
ExecuteGP(featureClassToFeatureClass as IGPProcess);
}
private void featureClassToGeodatabaseToolStripMenuItem_Click(object sender, EventArgs e)
{
ESRI.ArcGIS.ConversionTools.FeatureClassToGeodatabase featureClassToGeodatabase = new ESRI.ArcGIS.ConversionTools.FeatureClassToGeodatabase();
featureClassToGeodatabase.Input_Features = fileGDBPath + "\\" + sourceFCName;
featureClassToGeodatabase.Output_Geodatabase = sdePath;
ExecuteGP(featureClassToGeodatabase as IGPProcess);
}
private void copyFeaturesToolStripMenuItem_Click(object sender, EventArgs e)
{
ESRI.ArcGIS.DataManagementTools.CopyFeatures copyFeatures = new ESRI.ArcGIS.DataManagementTools.CopyFeatures();
copyFeatures.in_features = fileGDBPath + "\\" + sourceFCName;
copyFeatures.out_feature_class = sdePath + "\\" + targetFCName;
ExecuteGP(copyFeatures as IGPProcess);
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
ESRI.ArcGIS.DataManagementTools.Copy copy = new ESRI.ArcGIS.DataManagementTools.Copy();
copy.in_data = fileGDBPath + "\\" + sourceFCName;
copy.out_data = sdePath + "\\" + targetFCName;
ExecuteGP(copy as IGPProcess);
}
}
}