GIS开发进阶之路(十五)ArcEngine字段小结、Maven

本文总结了ArcEngine中字段操作的方法,包括字段的创建、添加、修改、删除及批量赋值等关键步骤,并介绍了如何使用接口实现这些操作。此外,还提供了字段值的统计和读写方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArcEngine字段小结

  • 常用接口

    • IField、IField2
    • IFieldEdit、IFieldEdit2
    • ISchemaLock
    • IFields、IFields2
    • IFieldsEdit、IFieldsEdit2
  • 添加字段

    创建字段并添加到字段集中

    public IFields CreateFieldExample()
            {
                //1.新建IFields对象
                IFields pFields = new FieldsClass();
                //接口跳转到IFieldsEdit
                IFieldsEdit pFieldsEdit = (IFieldsEdit)pFields;
                //2.新建IField对象
                IField pField = new FieldClass();
                //接口跳转到IFieldEdit对象上进行编辑
                IFieldEdit2 pFieldEdit = (IFieldEdit2)pField;
                pFieldEdit.Name_2 = "FieldName";//Name属性只读,Name_2只写
                pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString;
                pFieldEdit.Length_2 = 50;
                //3.将新建的IField对象添加到IFieldsEdit中
                pFieldsEdit.AddField(pField);
    
                return pFields;
            }
        }
    

    将字段添加到已有的要素类中

    public void AddFieldToFeatureClass(IFeatureClass featureClass, IField field)
    
            {
                ISchemaLock schemaLock = (ISchemaLock)featureClass;//创建模式锁对象
                try
                {
                    //修改为独占锁
                    schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
                    //判断字段是否存在,存在则返回,不存在则添加
                    if (featureClass.FindField(field.Name) == -1)
                    {
                        // 添加字段
                        featureClass.AddField(field);
                    }
                }
                catch (Exception ex)
                {
                    // 输出异常
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    // 修改为共享锁
                    schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
                }
            }
    

    获取创建要素类所需的最少字段

    public IFields CreateFieldsCollectionForFeatureClass(ISpatialReference spatialReference)
            {
                //创建IFeatureClassDescription接口
                IFeatureClassDescription pFeaClassDesc = new FeatureClassDescriptionClass();
                IObjectClassDescription pObjClassDesc = (IObjectClassDescription)pFeaClassDesc;
    
                // 获取所需的字段集合
                IFields pFields = pObjClassDesc.RequiredFields;
    
                // 获取几何字段
                int iShapeFieldIndex = pFields.FindField(pFeaClassDesc.ShapeFieldName);
                IField pShapeField = pFields.get_Field(iShapeFieldIndex);
    
                // 获取几何定义
                IGeometryDef pGeometryDef = pShapeField.GeometryDef;
                IGeometryDefEdit pGeometryDefEdit = (IGeometryDefEdit)pGeometryDef;
    
                // 修改要素类的集合类型为线(默认为面)
                pGeometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolyline;
                pGeometryDefEdit.HasM_2 = true;
                pGeometryDefEdit.GridCount_2 = 1;
    
                //设置格网大小为(0,0)
                pGeometryDefEdit.set_GridSize(0, 0);
                //设置坐标系
                pGeometryDefEdit.SpatialReference_2 = spatialReference;
    
                // 创建IFieldsEdit对象
                IFieldsEdit pFieldsEdit = (IFieldsEdit)pFields;
    
                // 创建自定义的字段
                IField incomeField = new FieldClass();
                IFieldEdit incomeFieldEdit = (IFieldEdit)incomeField;
                incomeFieldEdit.AliasName_2 = "Average income for 1999-2000";
                incomeFieldEdit.Editable_2 = true;//可编辑
                incomeFieldEdit.IsNullable_2 = false;//不允许为空
                incomeFieldEdit.Name_2 = "average_income";//字段名称
                incomeFieldEdit.Precision_2 = 2;//字段精度
                incomeFieldEdit.Scale_2 = 5;
                incomeFieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;//字段类型
                //添加自定义字段
                pFieldsEdit.AddField(incomeField);
    
                return pFields;
            }
    

    验证字段

    public IFields ValidateFieldsForWorkspace(IFields fields, IWorkspace workspace)
            {
                // 创建IFieldChecker对象.
                IFieldChecker pFieldChecker = new FieldCheckerClass();
                pFieldChecker.ValidateWorkspace = workspace;
                // 验证字段集
                IEnumFieldError enumFieldError = null;
                IFields validatedFields = null;
                pFieldChecker.Validate(fields, out enumFieldError, out validatedFields);
                // 显示字段错误
                IFieldError fieldError = null;
                enumFieldError.Reset();
                while ((fieldError = enumFieldError.Next()) != null)
                {
                    IField errorField = fields.get_Field(fieldError.FieldIndex);
                    Console.WriteLine("Field '{0}': Error '{1}'", errorField.Name, fieldError.FieldError);
                }
                //返回验证的字段
                return validatedFields;
            }
    
  • 修改字段

    修改字段有两种方法,一种是调用接口IFieldEdit2,另外一种是调用GP工具(ArcMap中位置:Data Management Tools\Fields\AlterField)。

    //更新字段的第一种方法,调用IFieldEdit2接口(属性后面带“_2”的代表只写,不带“_2”的代表只读)
            public void UpdateField(IField pInField)
            {
                IFieldEdit2 pFieldEdit = pInField as IFieldEdit2;
                pFieldEdit.Name_2 = "NewName";
                pFieldEdit.AliasName_2 = "NewAlias";
                pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString;
                pFieldEdit.Length_2 = pFieldEdit.Length + 50;
                pFieldEdit.IsNullable_2 = !pFieldEdit.IsNullable;
                //......
            }
            //更新字段的第二种方法,调用GP工具,代码略
    
  • 删除字段

    删除字段有两种方法,一种是调用接口IFieldsEdit,另外一种是调用GP工具,(ArcMap中位置:Data Management Tools\Fields\DeleteField)。

    //删除字段的第一种方法,调用IFieldsEdit接口
            public void DeleteField(IFields pInFields,IField pDeleteField)
            {
                IFieldsEdit pFieldsEdit = pInFields as IFieldsEdit;
                pFieldsEdit.DeleteAllFields();//删除全部字段
                pFieldsEdit.DeleteField(pDeleteField);//删除指定字段
            }
    
            //官方版示例,开始模式锁,然后再删除字段
            public void DeleteField(IObjectClass objectClass, String fieldName)
            {
                // Get the field to be deleted.
                int fieldIndex = objectClass.FindField(fieldName);
                IField field = objectClass.Fields.get_Field(fieldIndex);
                // Cast to the ISchemaLock interface.
                ISchemaLock schemaLock = (ISchemaLock)objectClass;
                try
                {
                    // Get an exclusive schema lock on the object class. 
                    schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
                    // Alter the class extension for the class.
                    objectClass.DeleteField(field);
                }
                catch (Exception e)
                {
                    // An error was raised; therefore, notify the user.
                    Console.WriteLine(e.Message);
                }
                finally
                {
                    // Since the Finally block is always called, the exclusive lock is demoted
                    // to a shared lock after the field is deleted and after an error is raised.
                    schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
                }
            }
            //删除字段的第二种方法,调用GP工具,代码略
    
  • 字段批量赋值

    字段批量赋值有三种方法:①遍历数据,然后用游标查询进行赋值 ②利用GP工具CalculateField进行批量赋值 ③利用IWorkspace的ExcuteSQL执行Update语句进行批量赋值。(具体代码略)
    效率对比:③>②>①

  • 遍历字段

    //遍历字段
            public void TraversalQuery(IFields pFields)
            {
                for (int i = 0; i < pFields.FieldCount; i++)
                {
                    IField pField = pFields.get_Field(i);
                    //......
                }
            }
    
            //获取字段的总数
            public int GetFieldsCount(IFields pFields)
            {
                IFieldsEdit pFieldsEdit = pFields as IFieldsEdit;
                return pFieldsEdit.FieldCount;
            }
    
  • 读取字段值列表

    public List<string> GetFieldUniqueValue(ITable pTable, string sFieldName, IQueryFilter pQueryFilter = null)
            {
                if (pTable == null || pTable.FindField(sFieldName) < 0)
                {
                    return null;
                }
                List<string> valuesList = new List<string>();
                using (ComReleaser pComReleaser = new ComReleaser())
                {
                    ICursor pCursor = pTable.Search(pQueryFilter, true);
                    pComReleaser.ManageLifetime(pCursor);
                    IDataStatistics pDataStats = new DataStatisticsClass();
                    pComReleaser.ManageLifetime(pDataStats);
                    pDataStats.Cursor = pCursor;
                    pDataStats.Field = sFieldName;
                    IEnumerator pEnumValues = pDataStats.UniqueValues;
                    pComReleaser.ManageLifetime(pEnumValues);
                    pEnumValues.Reset();
                    while (pEnumValues.MoveNext())
                    {
                        object objValue = pEnumValues.Current;
                        if (objValue == null || Convert.IsDBNull(objValue))
                        {
                            continue;
                        }
                        valuesList.Add(objValue.ToString());
                    }
                }
                return valuesList;
            }
    
            public List<string> GetFieldUniqueValue(IFeatureWorkspace pFeaWs, string sTableName,
                string sFldName, string sWhere = "")
            {
                List<string> values = new List<string>();
                using (ComReleaser pComreleaser = new ComReleaser())
                {
                    IQueryDef pQueryDef = pFeaWs.CreateQueryDef();
                    pComreleaser.ManageLifetime(pQueryDef);
                    pQueryDef.Tables = sTableName;
                    pQueryDef.SubFields = "DISTINCT(" + sFldName + ")";
                    if (sWhere != "")
                    {
                        pQueryDef.WhereClause = sWhere;
                    }
                    ICursor pCursor = pQueryDef.Evaluate();
    
                    IRow pRow = null;
                    while ((pRow = pCursor.NextRow()) != null)
                    {
                        string sValue = CommonAPI.ConvertToString(pRow.get_Value(0));
                        values.Add(sValue);
                    }
                    return values;
                }
            }
    
  • 字段值统计

    参考https://www.cnblogs.com/lauer0246/archive/2008/08/01/1258109.html

  • blob字段的读写

    //读取blob字段到字符串中
            public  string ReadStringFromBlob(object objValue)
            {
                string sResault = "";
                IMemoryBlobStreamVariant pMemoryBlobStreamVariant = objValue as IMemoryBlobStreamVariant;
                if (pMemoryBlobStreamVariant != null)
                {
                    pMemoryBlobStreamVariant.ExportToVariant(out objValue);
                    sResault = Encoding.Default.GetString(objValue as byte[]);
                }
                return sResault;
            }
    
            //读取Blob字段中的二进制字节数组
            public  byte[] ReadBytesFromBlob(object objValue)
            {
                IMemoryBlobStreamVariant pMemoryBlobStreamVariant = objValue as IMemoryBlobStreamVariant;
                if (pMemoryBlobStreamVariant != null)
                {
                    pMemoryBlobStreamVariant.ExportToVariant(out objValue);
                }
                byte[] bytes = objValue as byte[];
                return bytes;
            }
    
            //将字符串写入Blob流对象
            public  IMemoryBlobStream WriteStringToBlob(string sValue)
            {
                IMemoryBlobStream blobStream = new MemoryBlobStreamClass();
                if (!string.IsNullOrWhiteSpace(sValue))
                {
                    object objValue = Encoding.Default.GetBytes(sValue);
                    (blobStream as IMemoryBlobStreamVariant).ImportFromVariant(objValue);
                }
                return blobStream;
            }
    
            //将字节数组写入Blob流对象
            public  IMemoryBlobStream WriteBytesToBlob(byte[] bytes)
            {
                IMemoryBlobStream blobStream = new MemoryBlobStreamClass();
                (blobStream as IMemoryBlobStreamVariant).ImportFromVariant(bytes);
                return blobStream;
            }       
    
            //将Object对象写入到Blob字段中
            public  void SaveBlobValue(IRowBuffer rowBuffer, int iFieldIndex, object value)
            {
                if (value is IPersistStream)
                {
                    IMemoryBlobStream pBlobStream = new MemoryBlobStreamClass();
                    (value as IPersistStream).Save(pBlobStream, 0);
                    rowBuffer.set_Value(iFieldIndex, pBlobStream);
                }
                else
                {
                    IMemoryBlobStream pBlobStream = new MemoryBlobStreamClass();
                    rowBuffer.set_Value(iFieldIndex, pBlobStream);
                }
            }
    
  • 字段的拷贝

     public IField CopyField(IField pInField)
            {
                IField pOutField = (pInField as ESRI.ArcGIS.esriSystem.IClone).Clone() as IField;
                return pOutField;
            }
    

Maven

简介

java包管理和构建工具

一个使用Maven管理的普通的Java项目,它的目录结构默认如下:

a-maven-project
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   └── resources
│   └── test
│       ├── java
│       └── resources
└── target

pom.xml是maven的项目描述文件

<project ...>
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.itranswarp.learnjava</groupId>
	<artifactId>hello</artifactId>
	<version>1.0</version>
	<packaging>jar</packaging>
	<properties>
        ...
	</properties>
	<dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
	</dependencies>
</project>

依赖管理

依赖关系

Maven定义了几种依赖关系,分别是compiletestruntimeprovided

scope说明示例
compile编译时需要用到该jar包(默认)commons-logging
test编译Test时需要用到该jar包junit
runtime编译时不需要,但运行时需要用到mysql
provided编译时需要用到,但运行时由JDK或某个服务器提供servlet-api

其中,默认的compile是最常用的,Maven会把这种类型的依赖直接放入classpath。

test依赖表示仅在测试时使用,正常运行时并不需要。最常用的test依赖就是JUnit:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.3.2</version>
    <scope>test</scope>
</dependency>

runtime依赖表示编译时不需要,但运行时需要。最典型的runtime依赖是JDBC驱动,例如MySQL驱动:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
    <scope>runtime</scope>
</dependency>

provided依赖表示编译时需要,但运行时不需要。最典型的provided依赖是Servlet API,编译的时候需要,但是运行时,Servlet服务器内置了相关的jar,所以运行期不需要:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.0</version>
    <scope>provided</scope>
</dependency>

Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过,就会被Maven自动缓存在本地目录(用户主目录的.m2目录),所以,除了第一次编译时因为下载需要时间会比较慢,后续过程因为有本地缓存,并不会重复下载相同的jar包。

唯一ID

对于某个依赖,Maven只需要3个变量即可唯一确定某个jar包:

  • groupId:属于组织的名称,类似Java的包名;
  • artifactId:该jar包自身的名称,类似Java的类名;
  • version:该jar包的版本。

通过上述3个变量,即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改。修改已发布jar包的唯一方法是发布一个新版本。

构建流程

在实际开发过程中,经常使用的命令有:

mvn clean:清理所有生成的class和jar;

mvn clean compile:先清理,再执行到compile

mvn clean test:先清理,再执行到test,因为执行test前必须执行compile,所以这里不必指定compile

mvn clean package:先清理,再执行到package

大多数phase在执行过程中,因为通常没有在pom.xml中配置相关的设置,所以这些phase什么事情都不做。

经常用到的phase其实只有几个:

  • clean:清理
  • compile:编译
  • test:运行测试
  • package:打包

使用插件

如果标准插件无法满足需求,还可以使用自定义插件。使用自定义插件的时候,需要声明。例如,使用maven-shade-plugin可以创建一个可执行的jar,要使用这个插件,需要在pom.xml中声明它:

<project>
    ...
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
                <version>3.2.1</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
						<configuration>
                            ...
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

自定义插件往往需要一些配置,例如,maven-shade-plugin需要指定Java程序的入口,它的配置是:

<configuration>
    <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.itranswarp.learnjava.Main</mainClass>
        </transformer>
    </transformers>
</configuration>

注意,Maven自带的标准插件例如compiler是无需声明的,只有引入其它的插件才需要声明。

模块管理

对于Maven工程来说,原来是一个大项目:

single-project
├── pom.xml
└── src

可以看出来,模块A和模块B的pom.xml高度相似,因此,可以提取出共同部分作为parent

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itranswarp.learnjava</groupId>
    <artifactId>parent</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>

    <name>parent</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.28</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.5.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

注意到parent的<packaging>pom而不是jar,因为parent本身不含任何Java代码。编写parentpom.xml只是为了在各个模块中减少重复的配置。现在的整个工程结构如下:

multiple-project
├── pom.xml
├── parent
│   └── pom.xml
├── module-a
│   ├── pom.xml
│   └── src
├── module-b
│   ├── pom.xml
│   └── src
└── module-c
    ├── pom.xml
    └── src

这样模块A就可以简化为:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.itranswarp.learnjava</groupId>
        <artifactId>parent</artifactId>
        <version>1.0</version>
        <relativePath>../parent/pom.xml</relativePath>
    </parent>

    <artifactId>module-a</artifactId>
    <packaging>jar</packaging>
    <name>module-a</name>
</project>

模块B、模块C都可以直接从parent继承,大幅简化了pom.xml的编写。

如果模块A依赖模块B,则模块A需要模块B的jar包才能正常编译,需要在模块A中引入模块B:

    ...
    <dependencies>
        <dependency>
            <groupId>com.itranswarp.learnjava</groupId>
            <artifactId>module-b</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

最后,在编译的时候,需要在根目录创建一个pom.xml统一编译:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.itranswarp.learnjava</groupId>
    <artifactId>build</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>
    <name>build</name>

    <modules>
        <module>parent</module>
        <module>module-a</module>
        <module>module-b</module>
        <module>module-c</module>
    </modules>
</project>

这样,在根目录执行mvn clean package时,Maven根据根目录的pom.xml找到包括parent在内的共4个<module>,一次性全部编译。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值