使用GDAL为多要素图层添加字段后如何保存编辑内容?
问题描述
我用以下Python代码给Shapefile新增字段并修改字段值:
# -*- coding: utf-8 -*- import os from osgeo import gdal from osgeo import ogr root_path = "xxxxxxxxxxx" # root path if __name__=='__main__': gdal.UseExceptions() ogr.RegisterAll() gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8") gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") oDriver = ogr.GetDriverByName("ESRI Shapefile") file_list = os.listdir(root_path) for dir in file_list: if dir.endswith('.shp'): oDS = ogr.Open(root_path+dir, 0) lyr = oDS.GetLayer() LD = lyr.GetLayerDefn() lyr.ResetReading() print(LD.GetFieldCount()) if LD.GetFieldIndex('Item_Code') == -1: Field = ogr.FieldDefn('Item_Code', ogr.OFTString) Field.SetWidth(15) LD.AddFieldDefn(Field) print(lyr.schema[13].name) for feature in lyr: if dir.split('.')[0].startswith('GBZ'): print(feature.SetField('Item_Code', dir.split('.')[0][:15])) elif dir.split('.')[0].startswith('XM'): print(feature.SetField('Item_Code', dir.split('.')[0][:14])) else: print('error') print("once") print(lyr.SetFeature(feature)) print(lyr.SyncToDisk()) oDS.Destroy()
运行输出为:13, Item_Code, None, once, 6, 0。根据官方文档,错误码6对应OGRERR_FAILURE。脚本执行完后用QGIS查看Shapefile,没有任何修改生效。
执行print(lyr.schema[13].name)时能看到图层结构已更新,但无法保存修改。另外,Layer类的UpdateFeature、UpsertFeature方法无法调用,只能用Update方法,GDAL的ogr.Open()和gdal.OpenEx()相关API文档理解起来也比较困难。
环境信息:
- QGIS: 3.26.3
- Python: 3.7.9(64位)
- GDAL: 3.0.4
问题原因及修复方案
核心问题
- 只读模式打开数据源:
ogr.Open()第二个参数传0是只读模式,无法写入任何修改,这是保存失败的核心原因。 - 字段添加方式错误:直接修改
LayerDefn对象不会同步到磁盘,必须调用图层的CreateField()方法。 - 路径拼接不规范:用
root_path+dir拼接路径易出现分隔符问题,且可能因文件名含特殊字符报错。
修复后代码
# -*- coding: utf-8 -*- import os from osgeo import gdal from osgeo import ogr root_path = "xxxxxxxxxxx" # 根目录路径 if __name__=='__main__': gdal.UseExceptions() ogr.RegisterAll() gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8") gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") oDriver = ogr.GetDriverByName("ESRI Shapefile") for filename in os.listdir(root_path): if filename.endswith('.shp'): shp_path = os.path.join(root_path, filename) # 以可写模式打开数据源(参数1代表可写) oDS = ogr.Open(shp_path, 1) if not oDS: print(f"无法打开文件: {shp_path}") continue lyr = oDS.GetLayer() field_idx = lyr.GetLayerDefn().GetFieldIndex('Item_Code') if field_idx == -1: # 创建字段并添加到图层 field_def = ogr.FieldDefn('Item_Code', ogr.OFTString) field_def.SetWidth(15) if lyr.CreateField(field_def) != 0: print(f"添加字段失败: {shp_path}") oDS.Destroy() continue shp_name = os.path.splitext(filename)[0] # 遍历要素设置字段值 for feature in lyr: if shp_name.startswith('GBZ'): feature.SetField('Item_Code', shp_name[:15]) elif shp_name.startswith('XM'): feature.SetField('Item_Code', shp_name[:14]) else: print(f"文件名不符合规则: {filename}") continue # 更新要素到数据源 if lyr.SetFeature(feature) != 0: print(f"更新要素FID-{feature.GetFID()}失败") # 强制同步修改到磁盘 lyr.SyncToDisk() # 释放数据源资源 oDS.Destroy()
关键修改说明
- 可写模式打开:将
ogr.Open()的第二个参数改为1,获得写入权限,这是修改生效的前提。 - 规范添加字段:使用
lyr.CreateField()方法添加字段,这是OGR官方推荐的修改图层结构的方式。 - 路径优化:用
os.path.join()拼接路径,适配不同操作系统的路径规则。 - 错误检查:增加文件打开、字段创建、要素更新的错误判断,便于排查问题。
- 资源管理:确保所有修改操作完成后再释放数据源,避免未写入磁盘就关闭资源。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

