基于C#的ArcEngine二次开发29:GDB文件操作及异常处理

目录

1. ArcCatalog创建GDB、MDB、SHP

2. 代码创建gdb工作空间

2.1 CreateFileGDB Class创建

2.2 Acrivator.CreateInstance创建

2.2.1 实现代码

2.2.2 空间索引格网大小无效异常及解决方案

2.2.3 完善代码

3 GDB目录删除与资源释放

3.1 删除gdb文件

3.2 资源解除占用

3.2.1 杀死文件:

3.2.2 解除资源锁定:

3.2.3 资源释放问题

4 从gdb中拷贝图层到mdb中

4.1 从gdb中获取感兴趣图层

4.2 获取gdb感兴趣图层的图层名

4.3 打开mdb文件

4.4 判断要拷贝到mdb的文件是否存在

4.5 输出mdb图层名设置

4.6 字段赋值

4.7 设置几何定义

 4.8 满足条件的数据查询

4.9 数据转换



1. ArcCatalog创建GDB、MDB、SHP

  • 打开arccatalog

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第1张图片

  • 选择要建库的位置——右键——新建

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第2张图片

  • 文件地理数据库就是格式为gdb的数据

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第3张图片

  • 个人地理数据库就是格式为mdb的数据

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第4张图片

  • shapefile就是格式为shp的数据

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第5张图片

2. 代码创建gdb工作空间

2.1 CreateFileGDB Class创建

Creates a file geodatabase in a folder. [在给定目录下创建一个地理数据库]

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第6张图片

//创建GDB文件对象
CreateFileGDB process1 = new CreateFileGDB {out_folder_path = @"D:\新建文件夹", out_name = "temp.gdb"}

注意上述代码中为out_folder_path设定的目录必须是已存在的目录,否则在使用GP工具执行时,会报错:对COM组件的调用返回了错误 HRESULT E_FAIL

GP.Execute(processor1, null);//将创建的GDB文件加入到GP工具中

2.2 Acrivator.CreateInstance创建

2.2.1 实现代码

        /// 
        /// 在指定目录下创建gdb文件
        /// 
        /// 创建目录
        /// 返回工作空间
        public static IWorkspace CreateFileGdbWorkspace(string gdbFileName)
        {
            Type factoryType = Type.GetTypeFromProgID(
                "esriDataSourcesGDB.FileGDBWorkspaceFactory");

            IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance
                (factoryType);
            string path = System.IO.Path.GetDirectoryName(gdbFileName);
            string fileName = System.IO.Path.GetFileName(gdbFileName);

            IWorkspaceName workspaceName = workspaceFactory.Create(path, fileName, null, 0);
            IName name = (IName)workspaceName;
            IWorkspace workspace = (IWorkspace)name.Open();

            return workspace;
        }

2.2.2 空间索引格网大小无效异常及解决方案

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第7张图片

  • 错误:空间索引格网大小无效
  • 当通过 CreateFeature 和 Store 方法或使用 InsertCursor 创建新要素时,可能发生以下错误而导致创建失败:“FDO_E_INVALID_GRID_SIZE -2147216894 空间索引格网大小无效。”
  • 原因: 在创建要素的要素类的格网过小而无法处理要素,所以将出现 FDO_E_INVALID_GRID_SIZE 错误。 仅在使用文件地理数据库或 ArcSDE 地理数据库时会发生此错误。

根据错误消息出现方式的不同,可采用两种不同的方式来处理此错误。

  • 如果在 ArcMap 中进行编辑时出现此错误,可重新计算或修改要素类的格网大小以容纳新要素。 必须在 ArcCatalog 的“要素类”属性对话框中重新计算格网大小。 此操作需要使用“停止编辑”功能,保存一切更改并关闭包含要素类的地图文档。 有关如何重新计算或修改要素类格网大小的步骤,请参阅以下 Web 帮助文档:设置空间索引。
  • 如果在 ArcObjects API 中以编程方式遇到此错误,则通知用户手动修改空间索引不是理想的解决方案。 相反,可以在插入要素之前将要素类置于 LoadOnly 模式,以避免发生此错误。 当要素类退出 LoadOnly 模式时,地理数据库将自动重新计算适合的格网大小。 以下代码示例演示了如何将 LoadOnly 模式与要素类配合使用:

2.2.3 完善代码

            IQueryFilter filter = new QueryFilterClass();
            filter.WhereClause = "";
            IFeatureCursor pFeaturnCuesor = srcFeatureClass.Search(filter, false);
            IFeature pFeature = pFeaturnCuesor.NextFeature();

            IFeatureClassLoad dstFeaLoad = dstFeatureClass as IFeatureClassLoad;
            dstFeaLoad.LoadOnlyMode = true;

            while (pFeature != null)
            {

                IFeature dstFea = dstFeatureClass.CreateFeature();
                dstFea.Shape = pFeature.Shape;
                dstFea.Store();

                pFeature = pFeaturnCuesor.NextFeature();
            }

3 GDB目录删除与资源释放

3.1 删除gdb文件

gdb实际上是一个文件夹,所以要使用文件夹删除的方式删除

///dir为要删除的文件夹
public void deleteDir(string dir)
{
    try
    {
        Directory.Delete(dir, true);
    }
    catch
    {
        foreach (string file in Directory.GetFiles(dir))
        {
            FileInfo info = new FileInfo(file);
            info.Attributes = FileAttributes.Normal;
            File.Delete(file);
        }
        Directory.Delete(dir);
     }
}

代码二:

将IWorkspace转为IDataset,然后使用IDataset.Delete();进行删除。最好不要使用System.IO.File.Delete(path); 根据mdb或FileGDB的路径删除,这种方法可能删除不掉或者删不干净。

IDataset dataset = pWorkspace as IDataset; 
dataset.Delete();

注意:删除该workspace之前需要将使用到的FeatureClass,Feature,FeatureCursor,Field等AO对象先释放掉,可以使用System.Runtime.InteropServices.Marshal.FinalReleaseComObject();释放。

IWorkspaceFactory pWF = new FileGDBWorkspaceFactoryClass();
IWorkspace pW = pWF.OpenFromFile(gdbPath);
IFeatureWorkspace pWorkspace = pW as IFeatureWorkspace;

.....

IDataset dataset = pWorkspace as IDataset;
dataset.Delete();

3.2 资源解除占用

3.2.1 杀死文件:

            Process[] pcs = Process.GetProcesses();
            foreach (Process p in pcs)
            {
                if (p.MainModule.FileName == "你的文件路径")
                {
                    p.Kill();
                }
            } 

3.2.2 解除资源锁定:

ArcEngine /AO创建IWorkSpaceFactory的两种方式:

//第一种使用ae的工厂方法:
 IWorkspaceFactory pWsFactory = new ShapefileWorkspaceFactoryClass();
 IFeatureWorkspace  pWorkSpace = pWsFactory.OpenFromFile(path, 0) as IFeatureWorkspace;

//第二种使用C#的动态创建类型的方法:
Type typeObj=Type .GetTypeFromProgID("esriWorkspaceType.ShapefileWorkspaceFactoryClass" );
IWorkspaceFactory pWsFactory = (IWorkspaceFactory)Activator.CreateInstance(typeObj,null);
IFeatureWorkspace  pWorkSpace = pWsFactory.OpenFromFile(path, 0) as IFeatureWorkspace;

//关闭资源锁定  
IWorkspaceFactoryLockControl ipWsFactoryLock = IWorkspaceFactoryLockControl)pWsFactory; //pWsFactory可以是GDB/SHP/MDB
if(ipWsFactoryLock.SchemaLockingEnabled)
{
    ipWsFactoryLock.DisableSchemaLocking();
}

3.2.3 资源释放问题

AE中对MDB,SDE等数据库操作时,打开后却往往不能及时释放资源,导致别人操作提示对象被锁定。很多帖子说了很多原理,看的也烦且不实用,比如一句话概括的用System.Runtime.InteropServices.Marshal.ReleaseComObject(object o) 释放,说的很不清楚,很多人试过觉的释放不掉。事实上,的确是用该方法,但释放的技巧在于,新建几个AE对象就要逐步释放几个,例如:


IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass ();
IFeatureWorkspace Workspace = Fact.Open(Propset,0) as IFeatureWorkspace;
IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");
IFeatureLayer Fly = new FeatureLayerClass();

……
IFeature pf
IField pfield
……

再对象运行结束时释放,如:

System.Runtime.InteropServices.Marshal.ReleaseComObject(Fact)
System.Runtime.InteropServices.Marshal.ReleaseComObject(Workspace);
System.Runtime.InteropServices.Marshal.ReleaseComObject(Fcls);
System.Runtime.InteropServices.Marshal.ReleaseComObject(Fly);
System.Runtime.InteropServices.Marshal.ReleaseComObject(pf);
System.Runtime.InteropServices.Marshal.ReleaseComObject(pfield);

看到吧,千万不要以为你释放了等级最高的 IWorkspaceFactory, IWorkspace就算完事了。没办法,AE有时就这么难以理解的麻烦。

4 从gdb中拷贝图层到mdb中

主要是为了调用 IFeatureDataConverter.ConvertFeatureClass 方法:

public IEnumInvalidObject ConvertFeatureClass (
    IFeatureClassNameInputDatasetName,
    IQueryFilterInputQueryFilter,
    IFeatureDatasetNameoutputFDatasetName,
    IFeatureClassNameoutputFClassName,
    IGeometryDefOutputGeometryDef,
    IFieldsOutputFields,
    stringconfigKey,
    intFlushInterval,
    intparentHWND);

为了给该函数提供参数,进行如下步骤拆解:

  • 从gdb中获取感兴趣图层
  • 从gdb中获取感兴趣图层的名称
  • 打开mdb文件
  • 判断要拷贝文件是否存在,存在删除
  • 将gdb待拷贝图层字段赋值到mdb目标图层
  • 设置集合定义
  • 设置查询条件
  • 调用转换函数

4.1 从gdb中获取感兴趣图层

  • 打开工作空间工厂
  • 从文件中打开工作空间,将工作空间跳转为要素工作空间
  • 从要素工作空间中打开要素类
            IWorkspaceFactory workspaceFactory = new ESRI.ArcGIS.DataSourcesGDB.FileGDBWorkspaceFactoryClass();
            IWorkspace iworkspace = iworkspaceFactory.OpenFromFile(inPath, 0);
            IFeatureWorkspace ifeatureWorkspace = (IFeatureWorkspace)iworkspace;
            IFeatureClass ipFeaterClass = ifeatureWorkspace.OpenFeatureClass(checkLayerName);

4.2 获取gdb感兴趣图层的图层名

            IWorkspaceName inWorkspaceName = (inWorkspace as IDataset).FullName as IWorkspaceName ;     
            IFeatureClassName inFeatureClassName = new FeatureClassNameClass();
            IDatasetName inDatasetName = (IDatasetName)inFeatureClassName;
            inDatasetName.WorkspaceName = inWorkspaceName;
            inDatasetName.Name = gdbLayerName;

4.3 打开mdb文件

            IWorkspaceFactory oworkspaceFactory = new AccessWorkspaceFactory();
            IWorkspace oworkspace = oworkspaceFactory.OpenFromFile(inPath, 0);
            IFeatureWorkspace ofeatureWorkspace = (IFeatureWorkspace)workspace;
            IFeatureClass poFeaterClass = ofeatureWorkspace.OpenFeatureClass(mdbLayerName);

4.4 判断要拷贝到mdb的文件是否存在

            IWorkspace2 oworkspace2 = (IWorkspace2)oworkspace;
            if (oworkspace2.get_NameExists(esriDatasetType.esriDTFeatureClass, checkLayerName + "_超出图层检查结果"))
            {
                IFeatureClass pFC = ofeatureWorkspace.OpenFeatureClass(checkLayerName + "_超出图层检查结果");
                IDataset pDS = pFC as IDataset;
                pDS.Delete();
            }

4.5 输出mdb图层名设置

            IWorkspaceName ouWorkspaceName = (ouWorkspace as IDataset).FullName as IWorkspaceName ;     
            IFeatureClassName ouFeatureClassName = new FeatureClassNameClass();
            IDatasetName ouDatasetName = (IDatasetName)ouFeatureClassName;
            ouDatasetName.WorkspaceName = ouWorkspaceName;
            ouDatasetName.Name = mdbLayerName;

4.6 字段赋值

            
            IFieldChecker fieldChecker = new FieldCheckerClass();
            fieldChecker.InputWorkspace = iworkspace;//输入数据集工作空间
            fieldChecker.ValidateWorkspace = ouWorkpace;//输出工作空间

            IFields outFeatureClassFields;
            IEnumFieldError enumFieldError;            
            fieldChecker.Validate(inFeatureClassFields, out enumFieldError, out outFeatureClassFields);

4.7 设置几何定义

            IField geometryField =  outFeatureClassFields.get_Field(outFeatureClassFields.FindField(inFeatureClass.ShapeFieldName));
            IGeometryDef geometryDef = geometryField.GeometryDef;

 4.8 满足条件的数据查询

            //Set up the IQueryFilter to convert all the features by leaving a blank WhereClause
            QueryFilter qf = new QueryFilterClass();
            qf.WhereClause = "";

4.9 数据转换

IFeatureDataConverter fctofc = new FeatureDataConverterClass();
IEnumInvalidObject enumErrors = fctofc.ConvertFeatureClass(inFeatureClassName, qf, null, outFeatureClassName, geometryDef, outFeatureClassFields, "", 1000, 0);

参考资料:从FileGDB导出shp

5 其他代码积累

5.1 添加或删除字段

  ///   
    /// 删除属性表字段  
    ///   
    /// 需要添加字段的IFeatureLayer  
    /// 添加的字段的名称  
    ///   
    static public bool DeleteField(IFeatureLayer layer, string fieldName)  
    {  
        try  
        {  
            ITable pTable = (ITable)layer;  
            IFields pfields;  
            IField pfield;  
            pfields = pTable.Fields;  
            int fieldIndex = pfields.FindField(fieldName);  
            pfield = pfields.get_Field(fieldIndex);  
            pTable.DeleteField(pfield);  
            return true;  
        }  
  
  
        catch (Exception ex)  
        {  
            return false;  
        }  
    }  
 
///   
 /// 添加字段  
 ///   
 ///   
 ///   
 ///   
 ///   
 ///   
 static public bool AddField(IFeatureLayer layer, string fieldName, esriFieldType filedType, int fieldLength)  
 {  
     try  
     {  
         IFields pFields = layer.FeatureClass.Fields;  
         // IFieldsEdit pFieldsEdit = pFields as IFieldsEdit;  
         IFieldEdit pFieldEdit;  
  
         pFieldEdit = new FieldClass();  
         if (fieldName.Length > 5)  
             pFieldEdit.Name_2 = fieldName.Substring(0, 5);  
         else  
             pFieldEdit.Name_2 = fieldName;  
         pFieldEdit.Type_2 = filedType;  
         pFieldEdit.Editable_2 = true;  
         pFieldEdit.AliasName_2 = fieldName;  
         pFieldEdit.Length_2 = fieldLength;  
         ITable pTable = (ITable)layer;  
         pTable.AddField(pFieldEdit);  
         return true;  
         //   pFieldsEdit.AddField((IField)pFieldEdit);  
     }  
  
  
     catch (Exception ex)  
     {  
         return false;  
     }  
  
 }  

 

基于C#的ArcEngine二次开发29:GDB文件操作及异常处理_第8张图片

 

 

 

你可能感兴趣的:(基于C#的ArcEngine二次开发29:GDB文件操作及异常处理)