在ArcGIS Engine开发中,难免会遇到数据的转移,例如将shp文件、mdb、gdb中图层导入SDE,从SDE中导出图层。
尝试了下有以下几种方式:
一、普通方法
通过源数据集新建空数据集,并以IFeatureBuffer将源数据集中要素逐条插入新数据集。个人认为有以下优势:
1、可控制新建数据集的字段
2、可在插入记录时更改记录。如某个字段的映射
/// <summary>
/// 转换数据
/// </summary>
/// <param name="sourceFClass">源图层</param>
/// <param name="fname">目标图层名</param>
/// <param name="targetWS">目标工作空间</param>
/// <param name="spatialFilter">筛选条件</param>
public void TransferDataWithBuffer(IFeatureClass sourceFClass, string fname, IWorkspace targetWS, ISpatialFilter spatialFilter = null)
{
IFeatureWorkspace fwk = targetWS as IFeatureWorkspace;
//拷贝字段集合
IObjectCopy pObjectCopy = new ObjectCopyClass();
IFields pCopiedFields = pObjectCopy.Copy(sourceFClass.Fields) as IFields;
//Find the shape field.若不设置几何字段,导入数据的时候可能会报错
//int shapeFieldIndex = sourceFClass.FindField(sourceFClass.ShapeFieldName);
//IField shapeField = pCopiedFields.get_Field(shapeFieldIndex);
////var hasZ = shapeField.GeometryDef.HasZ;//是否含有Z值
////设置几何字段属性
//IGeometryDef pGeomDef = new GeometryDefClass();
//IGeometryDefEdit pGeomDefEdit = pGeomDef as IGeometryDefEdit;
//pGeomDefEdit.GeometryType_2 = shapeField.GeometryDef.GeometryType;
//pGeomDefEdit.SpatialReference_2 = shapeField.GeometryDef.SpatialReference;
//IFieldEdit pGeometryFieldEdit = shapeField as IFieldEdit;
//pGeometryFieldEdit.GeometryDef_2 = pGeomDefEdit;
//验证Fields
//IDataset inDataSet = sourceFClass as IDataset;
//IFields validatedFields = ValidateFields(sourceFClass.Fields, inDataSet.Workspace, targetWS);
//要数描述对象,能从中获取UID等属性
//IFeatureClassDescription fcDesc = new FeatureClassDescriptionClass();
//IObjectClassDescription ocDesc = (IObjectClassDescription)fcDesc;
//IFeatureClass targetFClass = fwk.CreateFeatureClass(fname, pCopiedFields, ocDesc.InstanceCLSID,
// ocDesc.ClassExtensionCLSID, esriFeatureType.esriFTSimple,fcDesc.ShapeFieldName, "");
//创建数据集
IFeatureClass targetFClass = fwk.CreateFeatureClass(fname, pCopiedFields, null, null, esriFeatureType.esriFTSimple, sourceFClass.ShapeFieldName, "");
//获取目标数据集对应源数据集索引字典 key:targetField value:sourceField
Dictionary<int, int> targetsource = new Dictionary<int, int>();
for (int i = 0; i < targetFClass.Fields.FieldCount; i++)
{
IField tField = targetFClass.Fields.get_Field(i);
if (!tField.Required) //目标图层的字段不是必须字段
{
int idx = sourceFClass.Fields.FindField(tField.Name);
if (idx > -1) //源要素类中该字段存在
targetsource.Add(i, idx);
}
}
//int FlushInterval = 1000;//清空缓冲区间隔
//int current = 0;//当前记录数
IFeatureCursor tCursor = targetFClass.Insert(true);
IFeatureBuffer tBuffer = targetFClass.CreateFeatureBuffer();
IFeatureCursor sCursor = sourceFClass.Search(spatialFilter, true);
IFeature sfeature = null;
object value;
while ((sfeature = sCursor.NextFeature()) != null)
{
tBuffer.Shape = sfeature.ShapeCopy;
foreach (KeyValuePair<int, int> keyValue in targetsource)
{
value = sfeature.Value[keyValue.Value];
//如果属性值是DBNull.Value类型的话,则不赋值,防止导出SHP是报错
if (value != DBNull.Value)
tBuffer.Value[keyValue.Key] = value;
}
tCursor.InsertFeature(tBuffer);
//current++;
//if (current % FlushInterval == 0)
// tCursor.Flush();
}
tCursor.Flush();
System.Runtime.InteropServices.Marshal.ReleaseComObject(sCursor);
System.Runtime.InteropServices.Marshal.ReleaseComObject(tBuffer);
System.Runtime.InteropServices.Marshal.ReleaseComObject(tCursor);
}
二、使用IFeatureDataConverter接口
1、IFeatureDataConverter将数据源中的单个表,要素类或要素数据集转换至另一个数据源中。
2、不能在目标字段集和中添加或删除字段,不然会导致转换失败,但是可以修改字段属性
3、仅加载简单的要素数据(点,线,多边形)
/// <summary>
/// 转换数据
/// </summary>
/// <param name="sourceFClass">源图层</param>
/// <param name="fname">目标图层名</param>
/// <param name="outws">目标工作空间</param>
/// <param name="spatialFilter">筛选条件</param>
public static void ConvertData(IFeatureClass sourceFClass, string fname, IWorkspace targetWS, ISpatialFilter spatialFilter = null)
{
//获取源数据集的名称对象
IDataset inDataSet = sourceFClass as IDataset;
IFeatureClassName sourceFeatureClassName = inDataSet.FullName as IFeatureClassName;
//获取目标工作空间名称对象
IDataset outDataSet = targetWS as IDataset;
IWorkspaceName targetWorkspaceName = outDataSet.FullName as IWorkspaceName;
// 创建目标数据集名称
IFeatureClassName targetFeatureClassName = new FeatureClassNameClass();
IDatasetName targetDatasetName = (IDatasetName)targetFeatureClassName;
targetDatasetName.Name = fname;
targetDatasetName.WorkspaceName = targetWorkspaceName;
IFields targetFields = ValidateFields(sourceFClass.Fields, inDataSet.Workspace, targetWS);
// Find the shape field.
int shapeFieldIndex = sourceFClass.FindField(sourceFClass.ShapeFieldName);
IField shapeField = sourceFClass.Fields.get_Field(shapeFieldIndex);
// 克隆源要素几何字段的几何定义
IGeometryDef geometryDef = shapeField.GeometryDef;
IClone geometryDefClone = (IClone)geometryDef;
IClone targetGeometryDefClone = geometryDefClone.Clone();
IGeometryDef targetGeometryDef = (IGeometryDef)targetGeometryDefClone;
// 将IGeometryDef强制转换为IGeometryDefEdit接口
//IGeometryDefEdit targetGeometryDefEdit = (IGeometryDefEdit)targetGeometryDef;
// 设置IGeometryDefEdit属性
//targetGeometryDefEdit.GridCount_2 = 1;
//targetGeometryDefEdit.set_GridSize(0, 0.75);
//targetGeometryDefEdit.GeometryType_2 = shapeField.GeometryDef.GeometryType;
//targetGeometryDefEdit.SpatialReference_2 = shapeField.GeometryDef.SpatialReference;
// 创建转换器并运行转换
IFeatureDataConverter featureDataConverter = new FeatureDataConverterClass();
IEnumInvalidObject enumInvalidObject = featureDataConverter.ConvertFeatureClass(sourceFeatureClassName, spatialFilter, null, targetFeatureClassName,
targetGeometryDef, targetFields, "", 1000, 0);
// 检查错误
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);
}
}
验证字段:
/// <summary>
/// 验证字段
/// </summary>
/// <param name="fields">字段集合</param>
/// <param name="sourceWk">源工作空间</param>
/// <param name="targetWk">目标工作空间</param>
/// <returns></returns>
public static IFields ValidateFields(IFields fields,IWorkspace sourceWk,IWorkspace targetWk)
{
// Create the objects and references necessary for field validation.
IFieldChecker fieldChecker = new FieldCheckerClass();
IFields sourceFields = fields;
IFields targetFields = null;
IEnumFieldError enumFieldError = null;
// Set the required properties for the IFieldChecker interface.
fieldChecker.InputWorkspace = sourceWk;
fieldChecker.ValidateWorkspace = targetWk;
// Validate the fields and check for errors.
fieldChecker.Validate(sourceFields, out enumFieldError, out targetFields);
var erro = "";
if (enumFieldError != null)
{
enumFieldError.Reset();
IFieldError fiderr = null;
while ((fiderr = enumFieldError.Next()) != null)
{
erro += $"错误类型【{fiderr.FieldError}】,字段名【{fields.Field[fiderr.FieldIndex].Name}】别名【{fields.Field[fiderr.FieldIndex].AliasName}】";
}
}
return targetFields;
}
三、使用IGeoDBDataTransfer接口
IGeoDBDataTransfer 接口用于一个或多个数据集从一个地理数据库复制到另一个地理数据库。这包括表格,要素类,要素数据集或任何其他类型的数据集以及包含不同类型数据集的集合
/// <summary>
/// IGeoDBDataTransfer接口在两个地理数据库之间复制数据
/// </summary>
/// <param name="dic">key:自定义数据集名称 value:数据集</param>
/// <param name="targetWS"></param>
private void DataTransfer(Dictionary<string,IFeatureClass> dic,IWorkspace targetWS)
{
// 获取目标工作空间名称对象
IDataset tdataset = targetWS as IDataset;
IWorkspaceName targetWorkspaceName = tdataset.FullName as IWorkspaceName;
IName targetName = (IName)targetWorkspaceName;
// 为要复制的数据集创建名称对象的枚举器
IEnumName sourceEnumName = new NamesEnumeratorClass();
IEnumNameEdit sourceEnumNameEdit = (IEnumNameEdit)sourceEnumName;
foreach(IFeatureClass it in dic.Values)
{
// 获取数据集的名称对象
IDataset sfdataset = it as IDataset;
IName sourceName = sfdataset.FullName;
// 将源要素名称对象加入枚举器
sourceEnumNameEdit.Add(sourceName);
}
// 创建geodbdatatransfer对象和空名称映射枚举器
IGeoDBDataTransfer geoDBDataTransfer = new GeoDBDataTransferClass();
IEnumNameMapping enumNameMapping = null;
// 使用geodbdatatransfer对象创建名称映射枚举器
bool conflictsFound = geoDBDataTransfer.GenerateNameMapping(sourceEnumName, targetName, out enumNameMapping);
enumNameMapping.Reset();
//检查是否有冲突
if (conflictsFound)
{
// 遍历每个名称映射
INameMapping nameMapping = null;
while ((nameMapping = enumNameMapping.Next()) != null)
{
// Resolve the mapping 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);
}
}
}
}
}
// 迭代对象名称并替换新名称或配置关键字
//enumNameMapping.Reset();
//INameMapping nameMapping = null;
//while ((nameMapping = enumNameMapping.Next()) != null)
//{
// //// Append a "_new" suffix to the mapping's target name.添加"_new"后缀
// //nameMapping.TargetName += "_new";
// nameMapping.TargetName = dic.FirstOrDefault(x => (x.Value as IDataset).Name.Equals(nameMapping.TargetName)).Key;
// //更改映射的目标名称可能会产生冲突。要防止出现错误,请在目标名称更改后检查映射是否存在冲突.为简单起见,前面的代码示例未显示此内容。
// //更改TargetName属性后,调用INameMapping.ValidateTargetName (目标的名称对象作为参数),然后检查NameConflicts属性。
// nameMapping.ValidateTargetName(targetName);
// if (nameMapping.NameConflicts)
// {
// nameMapping.TargetName = nameMapping.GetSuggestedName(targetName);
// }
// // Iterate through the mapping's children.
// IEnumNameMapping childEnumNameMapping = nameMapping.Children;
// if (childEnumNameMapping != null)
// {
// childEnumNameMapping.Reset();
// // Iterate through each child mapping.
// INameMapping childNameMapping = null;
// while ((childNameMapping = childEnumNameMapping.Next()) != null)
// {
// childNameMapping.TargetName += "_new";
// }
// }
//}
// Start the transfer.
geoDBDataTransfer.Transfer(enumNameMapping, targetName);
}
对比执行效率:
IFeatureBuffer | IFeatureDataConverter | IGeoDBDataTransfer | |
gdb--gdb | 25342ms | 24503ms | 28347ms |
gdb--mdb | 125321ms | 180722ms | 139120ms |
gdb--shp | 27969ms | 54444ms | 不支持 |
mdb--mdb | 149751ms | 154715ms | 172766ms |
mdb--gdb | 22146ms | 34357ms | 33599ms |
mdb--shp | 29098ms | 73460ms | 不支持 |
shp--shp | 36052ms | 51370ms | 不支持 |
shp--gdb | 27021ms | 26758ms | 不支持 |
shp--mdb | 176056ms | 113833ms | 不支持 |