# 2.2.shapefile的创建与要素插入

### 创建空的shapefile

创建一个shapefile文件使用的是`CreateFeatureclass_management`函数，其函数定义如下：

```
CreateFeatureclass_management(out_path, out_name, {geometry_type}, {template}, {has_m}, {has_z}, {spatial_reference}, {config_keyword}, {spatial_grid_1}, {spatial_grid_2}, {spatial_grid_3})
```

参数的定义如下：

| 参数                     | 说明                                                                                                                                                                      | 数据类型                       |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| out\_path              | 新创建的要素类（shapefile文件）所存放的目录，可以为ArcSDE 地理数据库、文件地理数据库、个人地理数据库或文件夹。此目录必须已经存在。                                                                                               | Workspace; Feature Dataset |
| out\_name              | 要创建的要素类的名称。                                                                                                                                                             | String                     |
| geometry\_type(可选)     | 要素类的几何类型。包括以下4种值：POINT、MULTIPOINT、POLYLINE、POLYGON，分别表示点要素、多点要素、线要素（包括多线、线环要素）、面要素（包括复杂面要素）。                                                                            | String                     |
| template               | 用以定义要素类属性的模板                                                                                                                                                            | Feature Layer              |
| has\_m(可选)             | 确定要素类是否包含线性测量值（m 值）。有以下3种值：DISABLED、ENABLED、SAME\_AS\_TEMPLATE， 分别表示输出要素类不具有 m 值、具有 m 值、与模板一致（仅当模板具有 m 值时，输出要素类才会具有 m 值）。                                               | String                     |
| has\_z(可选)             | 确定要素类是否包含高程值（z 值）。有以下3种值：DISABLED、ENABLED、SAME\_AS\_TEMPLATE，分别表示输出要素类不具有 z 值、具有 z 值、与模板一致（仅当模板具有 z 值时，输出要素类才会具有 z 值）。                                                  | String                     |
| spatial\_reference(可选) | 输出要素数据集的空间参考。                                                                                                                                                           | Spatial Reference          |
| config\_keyword(可选)    | 配置关键字仅适用于 ArcSDE 数据。它用于确定数据库表的存储参数。                                                                                                                                     | String                     |
| spatial\_grid\_1(可选)   | **空间格网 1、2 和 3** 参数用于计算空间索引，并且只适用于文件地理数据库和某些工作组与企业级地理数据库要素类。如果对设置格网大小不熟悉，则将这些选项保留为 0,0,0，然后 ArcGIS 会为您计算最佳大小。由于此工具未写入任何要素，因此空间索引将处于未构建状态。当使用诸如追加工具或编辑操作将要素写入要素类时，将构建索引。 | Double                     |
| spatial\_grid\_2(可选)   | 第二个空间格网的像元大小。如果您只需要一个格网，则将大小设置为 0。否则，至少将大小设置为比“spatial\_grid\_1”大三倍。                                                                                                    | Double                     |
| spatial\_grid\_3(可选)   | 第三个空间格网的像元大小。如果您只需要两个格网，则将大小设置为 0。否则，至少将大小设置为比“spatial\_grid\_3”大三倍。                                                                                                    | Double                     |

*引用自：*[*https://desktop.arcgis.com/zh-cn/arcmap/10.3/tools/data-management-toolbox/create-feature-class.htm*](https://desktop.arcgis.com/zh-cn/arcmap/10.3/tools/data-management-toolbox/create-feature-class.htm)

下面我们来创建一个点图层：

```
# 新建shapefile文件的文件名
new_shp_name = "create_new.shp"
# 使用WGS84坐标系
spatial_reference = arcpy.SpatialReference(4326)
# 新建shapefile文件所在的目录
dir_name = "../data/"
# 判断目录是否存在，如果不存在，则创建目录
if not os.path.exists(dir_name):
    os.mkdir(dir_name)
​
# 创建shapefile文件
arcpy.CreateFeatureclass_management(dir_name, out_name=new_shp_name, geometry_type='Point',
                                    spatial_reference=spatial_reference)
```

这段代码是在"上一级目录下的data文件夹中创建了一个名为**create\_new\.shp**的shapefile文件，各行的意思详见注释。目前这个shapefile依然是空的，不包含有任何要素，同样其属性表里也不包含有任何字段。

### 添加字段

我们创建了一个空的shapefile——**“../data/create\_new\.shp”**，其属性表里面没有任何属性信息（除了OID和Shape），下面我们将向这个文件中添加以下属性字段。添加字段使用的函数是`AddField_management`，其定义如下：

```
AddField_management (in_table, field_name, field_type, {field_precision}, {field_scale}, {field_length}, {field_alias}, {field_is_nullable}, {field_is_required}, {field_domain})
```

其定义如下：

| 参数                      | 说明                                                                                                                                                                                                                                                                                                                                                       | 数据类型                                                         |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| in\_table               | 需要添加字段的对象，包括 ArcSDE 的要素类、文件或个人地理数据库的要素类、coverage、shapefile、栅格目录、独立表、带属性表的栅格和/或图层。                                                                                                                                                                                                                                                                        | Mosaic Layer; Raster Catalog Layer; Raster Layer; Table View |
| field\_name             | 字段名                                                                                                                                                                                                                                                                                                                                                      | String                                                       |
| field\_type             | 字段类型，有以下几种值：**TEXT** ——字符串；**FLOAT** ——浮点型数字，值在 -3.4\*10^38 和 1.2\*10^38 之间的小数；**DOUBLE** —— 值在 -2.2\*10^308 和 1.8\*10^308 之间的小数；**SHORT**——短整型数字，值在 -32,768 和 32,767 之间的整数；**LONG**——长整型数字，值在 -2,147,483,648 和 2,147,483,647 之间的整数；**DATE**——日期和/或时间；**BLOB**——长度较长的一系列二进制数；**RASTER**——栅格影像，可以存储 ArcGIS 软件支持的所有栅格数据集格式，但强烈建议您仅使用小影像；**GUID**——全局唯一标识符。 | String                                                       |
| field\_precision(可选)    | 字段精度，储在字段中的位数。所有位都将被计算在内，而无论其处于小数点的哪一侧。如果输入表是个人或文件地理数据库，则将忽略字段精度值。                                                                                                                                                                                                                                                                                       | Long                                                         |
| field\_scale(可选)        | 小数位数，可存储在字段中的小数位数。此参数仅可用于浮点型和双精度数据字段类型。如果输入表是个人或文件地理数据库，则将忽略字段小数位数值。                                                                                                                                                                                                                                                                                     | Long                                                         |
| field\_length(可选)       | 字段长度。它为字段的每条记录设置最大允许字符数。此选项仅适用于文本或 blob 类型的字段。                                                                                                                                                                                                                                                                                                           | Long                                                         |
| field\_alias(可选)        | 字段别名，此名称用于为含义隐晦的的字段名称指定更具描述性的名称。字段别名参数仅适用于地理数据库和 coverage。                                                                                                                                                                                                                                                                                               | String                                                       |
| field\_is\_nullable(可选) | 是否可以为空。指定该字段是否可包含空值。空值与零或空字段不同，仅支持地理数据库中的字段。NON\_NULLABLE —字段不允许空值。NULLABLE —字段允许空值。这是默认设置。                                                                                                                                                                                                                                                              | Boolean                                                      |
| field\_is\_required(可选) | 是否为必填字段，仅支持地理数据库中的字段。NON\_REQUIRED —字段不是必填字段。这是默认设置。REQUIRED —此字段是必填字段。必填字段具有永久性，不能删除。                                                                                                                                                                                                                                                                   | Boolean                                                      |
| field\_domain(可选)       | 字段值域，用于约束地理数据库中的表、要素类或子类型的任何特定属性的允许值。必须指定现有属性域的名称才能将其应用于字段。                                                                                                                                                                                                                                                                                              | String                                                       |

*引用自：*[*https://desktop.arcgis.com/zh-cn/arcmap/10.3/tools/data-management-toolbox/add-field.htm*](https://desktop.arcgis.com/zh-cn/arcmap/10.3/tools/data-management-toolbox/add-field.htm)

通常情况下，我们所使用的数据类型为字符串（TEXT）和数字（FLOAT、DOUBLE、SHORT和LONG），对于字符串，其默认（也是最大）长度为255，我们可以通过指定`field_length`来进行约束；对于数字而已，我们不需要做任何处理即可。另外，受dBase数据库定义，字段名的长度最长为11个字节，而一般中文一个汉字使用两个字节来表示的，因此如果字段名全部用中文，则最多有5个汉字；对于英文、数字字符而言，每个字符都是一个字节表示的，因此如果字段名全部用英文、数字，则最多有11个字母/数字。

下面我们为前面创建的shapefile——**create\_new\.shp**——添加两个字段：

```
# 字段信息列表
# 元素的第一个值为字段名，第二个值为字段类型，如果字段为TEXT，第三个值为字符串的长度
field_info_list = [
    # 短整型字段id
    ('id', "SHORT"),
    # 字符串字段name，字符长度为10
    ('name', "TEXT", 10),
]
# 添加字段的shapefile路径
shp_file_Path = "../data/create_new.shp"
for field in field_info_list:
    # 判读字段类型是否为“TEXT”，并且指定了字段的长度
    if field[1] == "TEXT" and len(field) == 3:
        arcpy.AddField_management(shp_file_Path, field[0], field[1], field_length=field[2])
    else:
        arcpy.AddField_management(shp_file_Path, field[0])
```

在这段代码中，我们为上一节创建的shapefile添加了两个字段：

1. id：短整型
2. name：字符串，长度为10

### 添加要素

每一个要素包含有空间信息和属性信息两个部分，空间信息就是要素中的一系列坐标信息，属性信息就是其属性表中的内容。要素的空间信息部分通过使用`arcpy.GeometryType`（GeometryType是泛指）的方法来创建，其包括以下5种方法：

```
arcpy.Point(x, y, z, m)/arcpy.PointGeometry(arcpy.Point)
arcpy.Multipoint(arcpy.Array)
arcpy.Polyline(arcpy.Array)
arcpy.Polygon(arcpy.Array)
```

**\*注：** 事实上，ArcPy中点要素的几何对应的应该是`arcpy.PointGeometry`，但是可以直接用`arcpy.Point`来作为点要素的几何部分，两者有一定的区别的。在概念上，`arcpy.Point`是几何对象的节点，是所有其他几何对象（PointGeometry、Multipoint、Polyline、Polygon）的基础，它的属性是x，y，z等值；`arcpy.PointGeometry`是一个点几何，`arcpy.Point`是其包含的一个节点（尽管只有这一个节点）；在属性和方法上，两者也不相同。详细请访问官网查看[Point](https://desktop.arcgis.com/zh-cn/arcmap/10.3/analyze/arcpy-classes/point.htm)和[PointGeometry](https://desktop.arcgis.com/zh-cn/arcmap/10.3/analyze/arcpy-classes/pointgeometry.htm)的定义。

当我们创建号一个要素后，需要将其插入到shapefile中，为此我们需要使用`arcpy.da.InsertCursor`函数来创建一个像要素类中追加数据的游标。其定义很简单：

```
InsertCursor(in_table, field_names)
```

| 参数                              | 说明                  | 数据类型   |
| ------------------------------- | ------------------- | ------ |
| in\_table                       | 要进行操作的要素类、图层、表或表视图。 | String |
| field\_names\[field\_names,...] | 字段名称列表（或组）。与前述相同    | string |

#### 点要素

之前创建的**create\_new\.shp**是个点要素图层，因此里面只能添加点要素。接下来我们想其中添加四个点点：

```
# 需要插入要素点的空间坐标
xy_array = [
    (110, 31),
    (112, 31),
    (112, 34),
    (110, 34),
]
# 需要向新shapefile中添加的字段名数组
field_names = ['id', 'name']
insert_shp_file_Path = "../data/create_new.shp"
​
with arcpy.da.InsertCursor(insert_shp_file_Path, ['SHAPE@'] + field_names) as i_cur:
    feature_id = 0
    for xy in xy_array:
        # 创建一个feature的几何信息部分
        point = arcpy.Point(xy[0], xy[1])
        feature_name = 'name-'+str(feature_id)
        # 将要素的空间信息和属性信息关联，其顺序与InsertCursor中的字段顺序一致
        insert_row = [point, feature_id, feature_name]
        # 将要素的空间信息、属性信息写入到shapefile中
        i_cur.insertRow(insert_row)
        feature_id += 1
```

这一段代码向**create\_new\.shp**shapefile中插入了四个点要素，每个要素都有两个属性：id和name。在`InsertCursor`的字段列表里面，我们选择操作的字段为**SHAPE@**、**id**、**name**，在新建要素时，先创建了一个point几何，将其与属性信息按照**SHAPE@**、**id**、**name**顺序构建了一个list：insert\_row，然后通过`InsertCursor`的游标**i\_cur**执行**insertRow**方法将其写入到了shapefile中（`InsertCursor`函数会返回当前要素的objectid）。

现在结果如图 1所示：

![图 1](/files/-M68UM19r2wMZRLpsjEh)

#### 多点要素

按照创建点shapefile和添加字段的方法，创建一个**多点图层**，向其中添加两个多点要素的核心代码如下：

```python
with arcpy.da.InsertCursor(insert_shp_file_Path, ['SHAPE@'] + field_names) as i_cur:
    arcpy_point_list = [arcpy.Point(pt[0], pt[1]) for pt in xy_array]
    m_point1_array = arcpy.Array([arcpy_point_list[0], arcpy_point_list[1]])
    m_point2_array = arcpy.Array([arcpy_point_list[2], arcpy_point_list[3]])

​    m_point1 = arcpy.Multipoint(m_point1_array)
​    m_point2 = arcpy.Multipoint(m_point2_array)

​    insert_row1 = [m_point1, 0, 'm-name-0']
​    insert_row2 = [m_point2, 1, 'm-name-1']

​    i_cur.insertRow(insert_row1)
​    i_cur.insertRow(insert_row2)
```

结果如图 2所示：

![图 2](/files/-M68UM0mPfWZ3hAkTSBk)

#### 线要素

按照创建点shapefile和添加字段的方法，创建一个**线图层**，向其中添加两个线要素的核心代码如下：

```
with arcpy.da.InsertCursor(insert_shp_file_Path, ['SHAPE@'] + field_names) as i_cur:
    arcpy_point_list = [arcpy.Point(pt[0], pt[1]) for pt in xy_array]
    m_point1_array = arcpy.Array([arcpy_point_list[0], arcpy_point_list[1]])
    m_point2_array = arcpy.Array([arcpy_point_list[2], arcpy_point_list[3]])
​
    m_point1 = arcpy.Polyline(m_point1_array)
    m_point2 = arcpy.Polyline(m_point2_array)
​
    insert_row1 = [m_point1, 0, 'm-name-0']
    insert_row2 = [m_point2, 1, 'm-name-1']
​
    i_cur.insertRow(insert_row1)
    i_cur.insertRow(insert_row2)
```

你可以看到，除了 将`arcpy.Multipoint`换为`arcpy.Polyline`外，代码与多点要素没有任何区别。结果如图 3所示：

![图 3](/files/-M68UM1BY_gsb-OKBduG)

#### 多线要素

按照创建点shapefile和添加字段的方法，创建一个**线图层**，向其中添加一个多线要素的核心代码如下：

```
with arcpy.da.InsertCursor(insert_shp_file_Path, ['SHAPE@'] + field_names) as i_cur:
    arcpy_point_list = [arcpy.Point(pt[0], pt[1]) for pt in xy_array]
    polyline_part1 = arcpy.Array([arcpy_point_list[0], arcpy_point_list[1]])
    polyline_part2 = arcpy.Array([arcpy_point_list[2], arcpy_point_list[3]])
    m_polyline_array = arcpy.Array([polyline_part1, polyline_part2])
    
    m_polyline_geometry = arcpy.Polyline(m_polyline_array)
​
    insert_row1 = [m_polyline_geometry, 0, 'm-name-0']
​
    i_cur.insertRow(insert_row1)
```

创建多线要素的时选择的几何类型依然为**polyline**，只是在创建几何时，将原来的两个线部件`arcpy.Array`对象合并为一个**arcpy.Array**对象，再通过此对象创建Polyline几何。结果如图 4所示。

![图 4](/files/-M68UM18_Ol8ylSp2fHA)

#### 面要素

按照创建点shapefile和添加字段的方法，创建一个**面图层**，向其中添加一个面要素的核心代码如下：

```
with arcpy.da.InsertCursor(insert_shp_file_Path, ['SHAPE@'] + field_names) as i_cur:
    arcpy_point_list = [arcpy.Point(pt[0], pt[1]) for pt in xy_array]
    polygon_array = arcpy.Array(arcpy_point_list)
    polygon_geometry = arcpy.Polygon(polygon_array)
​
    insert_row1 = [polygon_geometry, 0, 'm-name-0']
​
    i_cur.insertRow(insert_row1)
```

创建一个简单的polygon其实与线要素相似，只需要将`arcpy.Polyline`换为`arcpy.Polygon`，但是一个面要素需要至少3点。结果如图 5所示。

![图 5](/files/-M68UM1AZeZZ33qQAzEu)

#### 多面要素

按照创建点shapefile和添加字段的方法，创建一个**面图层**，向其中添加一个多面要素的核心代码如下：：

```
with arcpy.da.InsertCursor(insert_shp_file_Path, ['SHAPE@'] + field_names) as i_cur:
    xy_array1 = [(110, 31), (110, 32), (112, 31)，(110, 31)]
    xy_array2 = [(113, 31), (114, 31), (114, 32)]
    
    polygon_part1 = arcpy.Array([arcpy.Point(pt[0], pt[1]) for pt in xy_array1])
    polygon_part2 = arcpy.Array([arcpy.Point(pt[0], pt[1]) for pt in xy_array2])
​
    polygon_geometry_array = arcpy.Array([polygon_part1, polygon_part2])
​
    polygon_geometry = arcpy.Polygon(polygon_geometry_array)
​
    insert_row1 = [polygon_geometry, 0, 'm-name-0']
​
    i_cur.insertRow(insert_row1)
```

多面要素与多线要素类似，都是在已有的**arcpy.Array**部件上再应用一次**arcpy.Array**，然后再创建arcpy.Polygon即可。结果如图 6所示。

![图 6](/files/-M68UM14XxcL9UjqLG3z)

创建带有洞的面要素其实与多面要素时相同的，洞的边与最外层多边形的边都是该面要素的部件，两者的区别是：面要素外部的shell上的点是**顺时针**排列的，内部环上的点是**逆时针**排列的。但是别担心，ArcGIS是比较智能的，为什么这么说呢？有两点：

1. 按照规定，每个面要素的的起点和终点应该是相同的，以实现闭合线环，但是如果你没有将其闭合（例如上述代码中的xy\_array2），ArcPy会帮你闭合，但是应当注意每次写的时候都闭合，以避免意外的发生。
2. ArcPy会自动帮你调整多边形点的顺序。**a、**&#x5982;果只有一个部件，则存调整为顺时针；**b、**&#x5982;果有多个部件，且部件间不相交，则部件上的点会被调整为顺时针；**c、**&#x5982;果有一个部件为另一个部件的内环，则内环上的点会被调整为逆时针存储；**d、**&#x5982;果两个部件相交而不重叠，则这两个部件会作为两个部件存储，但是每个部件都将减去相交的部分，如下图所示，两个相交的三角形，将会存储为两个部件，一个为左侧蓝色部分，另一个为右侧红色部分，其上的点都作为顺时针存储。（注，以上所讲的相交、重叠，均是指不考虑点的顺序（或者将其都看作为顺时针）的情况下的相交、重叠）

![图 7](/files/-M68UM160AsuOgMAx1Le)

### 小结

通过以上示例，我们可以看到通过arcpy创建shapefile是比较复杂的，远不如直接在ArcGIS中操作方便。我们通常在ArcGIS中创建初始的数据，然后通过ArcPy来进行一系列的分析，并将分析结果保存到硬盘上。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zxyao.gitbook.io/arcpy/2.2.-chuang-jian-xin-de-shapefile.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
