根据Excel表格建立Shp文件(开发详解及源代码)(转载)

经常有人问这样的问题:如何将Excel表格的数据转换成GIS的数据?使用桌面软件(ArcGIS Desktop)本身无法解决这个问题,但是通过开发即可实现!

根据Excel表格建立Shp文件主要是通过Excel表格中的数值信息,如用于表示点坐标的x值、y值以及一些属性信息,来建立一个shp数据文件,该文件中点的几何位置即为Excel表格中指定的数值,并根据要求添加一些相关的属性信息。
具体来讲,整个过程主要包括三个方面:导入Excel数据表、新建shp数据文件、添加数据(包括几何数据和属性数据)。下面就以根据Excel表格生成Shp点数据文件为例,来具体介绍整个过程中的各主要部分:

一、导入Excel数据表
导入Excel数据表主要有两种方式,一种是通过OleDb数据源的形式打开Excel表格,还有一种就是以Application的形式通过调用Excel对象来打开表格。由于采用OleDb数据源的形式比较具有通用性,使用这种方式不仅可以打开Excel表格,还可以打开Access数据库、SQL数据库等(具体调用方式稍有差别),下面主要介绍第一种方式:
首先,在全局变量中定义数据源连接对象,如下:
OleDbConnection oledbcConnection;//Excel连接
然后,添加一个菜单项或按钮用于打开Excel数据表,为其Click()事件添加如下代码:
 try


{

                OpenFileDialog openDG = new OpenFileDialog();


openDG.Title =
"
打开Excel表格";


openDG.Filter =
"Excel
表格(*.xls)|*.xls|CSV格式(*.csv)|*.csv|所有文件(*.*)|*.*";


openDG.ShowDialog();

                string filename;


filename = openDG.FileName;

                string strConn


=
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filename + ";Extended Properties=Excel 8.0";


oledbcConnection =
new OleDbConnection(strConn);


oledbcConnection.Open();

                DataTable table = new DataTable();


table = oledbcConnection.GetOleDbSchemaTable(
OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });


excelBookComboBoxEx.Items.Clear();

                foreach (DataRow dr in table.Rows)


{

excelBookComboBoxEx.Items.Add((String)dr["TABLE_NAME"]);


}


excelBookComboBoxEx.Text = excelBookComboBoxEx.Items[0].ToString();


}

            catch (Exception exception)


{

                MessageBox.Show(exception.Message);


}

其中,excelBookComboBoxEx为一个ComboBox组件,用于显示该Excel文件中的表名称(一个Excel文件中可能包含有很多表,而且每个表的名称都不一样,且第一个数据表的名称不一定就为“Sheet1”)。为了避免由于Excel文件中不存在该表名而出现错误,利用一个ComboBox组件将该Excel文件中所有的表名列出来。其中变量table中保存了该Excel表格的所有表格信息,所以“dr["TABLE_NAME"]”即为获取该行中对应的表名。
在excelBookComboBoxEx控件中选择Excel表格中要打开的Excel工作表后,通过一个数据库连接命令和前面定义的数据源连接来获得工作表中的数据。添加一个按钮用于确定打开Excel中某个工作表,为其Click()事件添加如下代码:

            try


{

                string sheetName = excelBookComboBoxEx.Text;

                string strCom = @" SELECT * FROM [" + sheetName + "]";

                OleDbDataAdapter myCommand = new OleDbDataAdapter(strCom, oledbcConnection);

                DataSet myDataSet = new DataSet();


myCommand.Fill(myDataSet,
"[" + sheetName + "]");


excelDataGridViewX.DataMember =
"[" + sheetName + "]";


excelDataGridViewX.DataSource = myDataSet;


}

            catch (Exception exception)


{

                MessageBox.Show(exception.Message);


}

上述代码中,excelDataGridViewX表示一个数据表格控件用于显示Excel表格中的数据。

二、新建shp数据文件

由于通过Excel表格来建立一个Shp点数据文件,可能会涉及到新建Shp数据文件,所有在此先介绍新建Shp数据文件的过程。新建一个Form用于表示创建Shp文件的界面,设置Form的Name属性为“CreateShpFile”,然后在该界面上添加如下图所示控件(红色字体表示该控件的名称):


现说明一下该窗体中主要的控件,filePathTextBox控件用于表示文件的路径,saveFileButton控件用于表示保存路径浏览,fileNameTextBox控件用于表示新建的文件名,shpTypeComboBox用于表示新建的数据类型(如Point、Polyline、Polygon等),创建按钮用于根据设置开始创建新的Shp文件,取消按钮用于取消创建新Shp文件。

首先,在全局变量中定义三个变量,如下代码:

        private AxMapControl axMapControl;

        private string filePath;

        private string fileName;

其中,axMapControl表示MapControl控件(主要用于将新建的数据文件添加至地图中),filePath为新建数据文件的路径,fileName为新建数据文件的名称。

更改CreateShpFile窗体的构造函数为如下:

public CreateShpFile(AxMapControl _axMapControl)

        {

            axMapControl = _axMapControl;

            InitializeComponent();

        }

这样在定义CreateShpFile类时就要求指定MapControl对象。

为保存文件路径按钮(saveFileButton)的Click()事件添加如下代码:

        private void saveFileButton_Click(object sender, EventArgs e)

        {

            try

            {

                SaveFileDialog saveDG = new SaveFileDialog();

                saveDG.Title = "新建Shp文件";

                saveDG.Filter = "Shp文件(*.shp)|*.shp";

                saveDG.ShowDialog();

                string saveFilePath = saveDG.FileName;

                int i = saveFilePath.LastIndexOf(@"\");

                int length = saveFilePath.Length;



                filePath = Microsoft.VisualBasic.Strings.Left(saveFilePath, i+1);

                filePathTextBox.Text = filePath;

                fileName = Microsoft.VisualBasic.Strings.Right(saveFilePath, length - i - 1);

                fileNameTextBox.Text = fileName;

            }

            catch(Exception e)

            {

                MessageBox.Show(e.Message);

            }

        }

在上述代码中,在保存的全路径名称saveFilePath通过符号“\”来区分文件路径及文件名。当更改filePathTextBox控件及fileNameTextBox控件中的文字内容时,相应要更改全局变量filePath和fileName,所以为filePathTextBox控件及fileNameTextBox控件的TextChanged()事件添加如下代码:

        private void filePathTextBox_TextChanged(object sender, EventArgs e)

        {

            filePath = filePathTextBox.Text;

        }



        private void fileNameTextBox_TextChanged(object sender, EventArgs e)

        {

            fileName = fileNameTextBox.Text;

        }

创建一个新的Shp数据文件可以通过IWorkspaceFactory接口和IFeatureWorkspace接口来实现,如下为“创建”按钮的Click()事件添加的代码:

        private void 创建_Click(object sender, EventArgs e)

        {

            IWorkspaceFactory pShpWksFact = new ShapefileWorkspaceFactory();

            IFeatureWorkspace pFeatWks;

            pFeatWks = (IFeatureWorkspace)pShpWksFact.OpenFromFile(filePath, 0);



            const string strShapeFieldName = "Shape";

            //定义属性字段

            IFields pFields;

            IFieldsEdit pFieldsEdit;

            pFields = new FieldsClass();

            pFieldsEdit = (IFieldsEdit)pFields;



            IField pField = new FieldClass();

            IFieldEdit pFieldEdit = new FieldClass();

            pFieldEdit.Name_2 = strShapeFieldName;

            pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;

            pField = (IField)pFieldEdit;

            //定义几何属性

            IGeometryDef pGeomDef = new GeometryDefClass();

            IGeometryDefEdit pGeomDefEdit = new GeometryDefClass();

            pGeomDefEdit = (IGeometryDefEdit)pGeomDef;

            switch (shpTypeComboBox.Text)

            {

                case "Point":

                    pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;

                    break;

                case "Polyline":

                    pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolyline;

                    break;

                case "Polygon":

                    pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolygon;

                    break;

                case "MultiPoint":

                    pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryMultipoint;

                    break;

                case "MultiPatch":

                    pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryMultiPatch;

                    break;

            }            

            pGeomDefEdit.SpatialReference_2 = (ISpatialReference)new UnknownCoordinateSystem();

            pFieldEdit.GeometryDef_2 = pGeomDef;         



            pFieldsEdit.AddField(pField);

            pFields = (IFields)pFieldsEdit;



            IFeatureClass pFeatureClass;

            pFeatureClass = pFeatWks.CreateFeatureClass(fileName, pFields, null, null, esriFeatureType.esriFTSimple, strShapeFieldName, "");

            //添加新建的数据至Map中            

            axMapControl.AddShapeFile(filePath, fileName);

            this.Hide();

        }

具体来说,创建Shp文件的过程分为四步:第一步,建立IWorkspaceFactory和IFeatureWorkspace工作空间(根据文件路径);第二步,定义数据的属性字段,默认要为其创建一个名为“Shape”的属性字段用于表示其几何形状,该字段格式esriFieldType.esriFieldTypeGeometry;第三步,定义几何属性,在前面已经指定了Shp数据的类型(点、线、面),在此需要定义其GeometryType并指定空间参考系统,默认为UnknownCoordinateSystem;第四步,在IFeatureWorkspace工作空间中创建Shp数据文件。



三、添加数据

在添加几何数据时,先定义IFeature对象,如下:

IFeature pFeature = pFeatureClass.CreateFeature();

如果创建点数据,则直接定义一个IPoint对象用于表示点,并设置该点的位置,如下:

                    IPoint pPoint = new PointClass();

                    pPoint.PutCoords(pointX, pointY);

如果为线或面数据,它们的边界由一系列点组成,可以使用IPointCollection接口来实现。

添加属性数据之前,必须保证有对应的属性字段,由于新建数据并没有添加其他的属性字段,所以根据要求Excel表格中指定的数据列来添加相应的字段。添加属性字段主要采用IField接口来实现,如下定义:

IField pfield = new FieldClass();

然后定义一个IFieldEdit对象来修改或设置字段相应信息(注意:对IField对象是无法直接修改的,属性字段的修改必须通过IFieldEdit来完成),如下定义:

IFieldEdit pfieldEdit = new FieldClass();

然后根据修改或添加需要,对IFieldEdit对象的属性进行相应修改,如下:

                    pfieldEdit.Name_2 = “新的字段”;

                    pfieldEdit.Type_2 = esriFieldType.esriFieldTypeString;

其中,IFieldEdit的Name_2属性表示设置字段名称(注意:不是Name属性,修改属性字段名称应使用Name_2属性),Type_2属性表示设置属性字段的数据类型(如String、Float、Double等)。

修改或设置某个数据(IFeature)的某个属性值可以直接通过IFeature.set_Value()方法来修改,也可以通过定义一个IField对象来修改,如下直接使用IFeature.set_Value()方法来修改的代码:

pFeature.set_Value(pFeature.Fields.FindField(fieldName), dataRow.Cells[fieldName].Value.ToString());

新建一个窗体,设置其Name为CreateShpFileBaseOnExcel,为其添加如下图所示控件:


其中大部分控件与前面介绍的新建Shp文件类似,在此介绍xComboBoxEx控件用于指定生成的Shp中点数据的X坐标值为Excel工作表第几列的单元格数值,同样yComboBoxEx控件用于指定点数据的Y坐标值为Excel工作表中哪一列的单元格数值,fieldListBox列表控件列出了Excel工作表中所有的列,若需要添加这些列的值为相应点数据的属性值,则点击 按钮将该列添加到右侧addFieldListBox列表控件中。当然,若不需要添加该列值,也可用点击 按钮将该列从右侧addFieldListBox列表控件中移到左侧fieldListBox列表控件。为这两个按钮addFieldButtonX和delFieldButtonX的Click()事件添加如下代码:

private void delFieldButtonX_Click(object sender, EventArgs e)

        {

            if (addFieldListBox.SelectedItem != null)

            {

                fieldListBox.Items.Add(addFieldListBox.SelectedItem);

                addFieldListBox.Items.Remove(addFieldListBox.SelectedItem);

            }

        }



        private void addFieldButtonX_Click(object sender, EventArgs e)

        {

            if (fieldListBox.SelectedItem != null)

            {

                addFieldListBox.Items.Add(fieldListBox.SelectedItem);

                fieldListBox.Items.Remove(fieldListBox.SelectedItem);

            }

        }

同样,定义全局变量并修改构造函数,如下代码:

        private DevComponents.DotNetBar.Controls.DataGridViewX excelDataGridViewX;

        private AxMapControl axMapControl;

        private string filePath;

        private string fileName;



        public CreateShpFileBaseOnExcel(AxMapControl _axMapControl, DevComponents.DotNetBar.Controls.DataGridViewX _excelDataGridViewX)

        {

            axMapControl = _axMapControl;

            excelDataGridViewX=_excelDataGridViewX;

            InitializeComponent();

        }

其中,excelDataGridViewX变量用于表示Excel工作表中获取的数据表,接下来要获取数据(如点的X坐标、Y坐标等)都直接从该变量中获取。

在窗体的Load()事件中,为xComboBoxEx、yComboBoxEx和fieldListBox等控件添加项,如下代码:

        private void CreateShpFile_Load(object sender, EventArgs e)

        {

            for (int i = 0; i < excelDataGridViewX.Columns.Count; i++)

            {

                string headerString=excelDataGridViewX.Columns[i].HeaderText;

                xComboBoxEx.Items.Add(headerString);

                yComboBoxEx.Items.Add(headerString);

                fieldListBox.Items.Add(headerString);

            }

        }

此时,根据Excel表格建立Shp文件在新建Shp文件的基础上增加了添加属性字段、添加几何数据和添加属性数据,如下代码所示:

        private void 创建_Click(object sender, EventArgs e)

        {            

            try

            {

                IWorkspaceFactory pShpWksFact = new ShapefileWorkspaceFactory();

                IFeatureWorkspace pFeatWks;

                pFeatWks = (IFeatureWorkspace)pShpWksFact.OpenFromFile(filePath, 0);



                const string strShapeFieldName = "Shape";



                //定义属性字段

                IFields pFields;

                IFieldsEdit pFieldsEdit;

                pFields = new FieldsClass();

                pFieldsEdit = (IFieldsEdit)pFields;



                IField pField = new FieldClass();

                IFieldEdit pFieldEdit = new FieldClass();

                pFieldEdit.Name_2 = strShapeFieldName;

                pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;

                pField = (IField)pFieldEdit;

                //定义几何属性

                IGeometryDef pGeomDef = new GeometryDefClass();

                IGeometryDefEdit pGeomDefEdit = new GeometryDefClass();

                pGeomDefEdit = (IGeometryDefEdit)pGeomDef;

                pGeomDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;



                pGeomDefEdit.SpatialReference_2 = (ISpatialReference)new UnknownCoordinateSystem();

                pFieldEdit.GeometryDef_2 = pGeomDef;



                pFieldsEdit.AddField(pField);

                pFields = (IFields)pFieldsEdit;



                IFeatureClass pFeatureClass;

                pFeatureClass = pFeatWks.CreateFeatureClass(fileName, pFields, null, null, esriFeatureType.esriFTSimple, strShapeFieldName, "");



                //添加属性字段群

                for (int i = 0; i < addFieldListBox.Items.Count; i++)

                {

                    IField pfield = new FieldClass();

                    IFieldEdit pfieldEdit = new FieldClass();

                    pfieldEdit.Name_2 = addFieldListBox.Items[i].ToString();

                    pfieldEdit.Type_2 = esriFieldType.esriFieldTypeString;

                    pfield = (IField)pfieldEdit;

                    pFeatureClass.AddField(pfield);

                }



                //绘制点

                for(int i=0;i<excelDataGridViewX.Rows.Count-1;i++)

                {

                    DataGridViewRow dataRow = excelDataGridViewX.Rows[i];

                    double pointX, pointY;

                    pointX = double.Parse(dataRow.Cells[xComboBoxEx.Text].Value.ToString());

                    pointY = double.Parse(dataRow.Cells[yComboBoxEx.Text].Value.ToString());



                    IPoint pPoint = new PointClass();

                    pPoint.PutCoords(pointX, pointY);



                    IFeature pFeature = pFeatureClass.CreateFeature();

                    pFeature.Shape = pPoint;

                    //为该点添加所有的属性值

                    for (int j = 0; j < addFieldListBox.Items.Count; j++)

                    {

                        string fieldName = addFieldListBox.Items[j].ToString();

                        pFeature.set_Value(pFeature.Fields.FindField(fieldName), dataRow.Cells[fieldName].Value.ToString());

                    }

                    pFeature.Store();

                }



                //添加新建的数据至Map中            

                axMapControl.AddShapeFile(filePath, fileName);

                this.Hide();

            }

            catch (Exception exception)

            {

                MessageBox.Show("创建数据文件错误或属性字段错误!\n绘制点时错误!可能有空的数据行或指定X和Y的列中为非数字!\n"

                    + exception.Message);

                this.Hide();

            }

        }

在主窗体中调用该功能,直接定义一个CreateShpFileBaseOnExcel对象即可,如下:
 CreateShpFileBaseOnExcel createShpFileBaseOnExcel = new CreateShpFileBaseOnExcel(axMapControl1,excelDataGridViewX);

            createShpFileBaseOnExcel.ShowDialog();

其中,axMapControl1为主窗体中的MapControl控件,excelDataGridViewX为主窗体中用于显示Excel工作表的控件。
转载自http://bbs.esrichina-bj.cn/ESRI/thread-54689-1-1.html

原文地址:https://www.cnblogs.com/atravellers/p/1647731.html