使用GDAL访问Shapefile时无法正确读取属性表的问题
问题描述
我用以下Python代码读取Shapefile:
import os from osgeo import gdal from osgeo import ogr from osgeo import osr shp_path = "xxxxxxxx" if __name__=='__main__': ogr.RegisterAll() gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8") gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES") oDriver = ogr.GetDriverByName("ESRI Shapefile") path_list= os.listdir(shp_path) for dir in path_list: if dir.endswith('.shp'): oDS = oDriver.Open(dir, 0) iLayerCount = oDS.GetLayerCount() out_lyr = oDS.GetLayerByIndex(0) print(dir, iLayerCount, out_lyr.schema.len(), out_lyr.schema[0].name)
执行后输出:
"GBZ2012371002CZ.shp",1,1,'Item_Code'
但在QGIS中打开该Shapefile的属性表时,能看到大量字段。我怀疑代码没正确访问Shapefile的真实内容,想搞清楚GDAL Layer和QGIS显示内容的关系。
环境信息:
- QGIS: 3.26.3
- Python: 3.7.9(64位)
- GDAL: 3.0.4
后来发现Item_Code字段是我之前误操作生成的:当时错误地用Driver.CreateDataSource而非Driver.Open加载文件,还通过DataSource.CreateLayer创建图层并添加了这个字段。我现在需要找到正确读取QGIS属性表中真实数据的方法。
另外,当我切换到没有生成过Item_Code字段的文件夹时,代码报错:
'NoneType' object has no attribute 'GetLayerCount'
看起来oDS完全无法访问属性表内容。
解决方案
1. 修复文件路径问题
报错'NoneType' object has no attribute 'GetLayerCount'的核心原因是:os.listdir(shp_path)返回的是文件夹内的文件名,而非完整路径,直接传给oDriver.Open()会导致GDAL找不到文件,返回None。
修改路径拼接逻辑:
for filename in path_list: if filename.endswith('.shp'): # 拼接完整文件路径 full_shp_path = os.path.join(shp_path, filename) oDS = oDriver.Open(full_shp_path, 0) if not oDS: print(f"无法打开文件: {full_shp_path}") continue # 后续读取操作
2. 清理误操作生成的冗余文件
之前用CreateDataSource的误操作会生成额外的Shapefile关联文件(比如冗余的.dbf、.shx),甚至覆盖原始文件,导致GDAL读取到错误图层。需要:
- 删除误操作生成的冗余文件,保留原始Shapefile的完整文件集(
.shp、.shx、.dbf、.prj等缺一不可) - 若原始
.dbf已被覆盖,需要从备份恢复或重新获取原始Shapefile
3. 正确读取属性字段的完整代码
修复后的可运行代码:
import os from osgeo import gdal from osgeo import ogr from osgeo import osr shp_path = "你的Shapefile文件夹路径" if __name__=='__main__': 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(shp_path): if filename.endswith('.shp'): full_path = os.path.join(shp_path, filename) oDS = oDriver.Open(full_path, 0) if not oDS: print(f"打开失败: {full_path}") continue layer_count = oDS.GetLayerCount() print(f"\n文件: {filename}, 图层数: {layer_count}") # 读取第一个图层的所有属性字段 layer = oDS.GetLayerByIndex(0) if not layer: print(f"获取图层失败: {filename}") continue schema = layer.schema print(f"字段总数: {schema.len()}") print("字段详情:") for field in schema: print(f"- 字段名: {field.name}, 类型: {field.GetTypeName()}") oDS.Destroy()
GDAL Layer与QGIS内容的对应关系
QGIS加载Shapefile时,底层也是调用GDAL/OGR库,二者的核心对象完全对应:
- QGIS中的可视化图层 = GDAL中的
ogr.Layer对象 - QGIS属性表的字段 = GDAL中的
ogr.FieldDefn对象 - 你之前看到的字段不一致,是因为误操作生成的冗余文件被GDAL读取,而非原始Shapefile数据。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

