读取多层嵌套ZIP内shapefile到GeoPandas报文件不存在错误
问题原因
- 代码中打印出的
name3只是最内层ZIP包内记录的文件名字符串,对应的shapefile从未被解压到脚本运行的本地工作目录,直接将该字符串传入gpd.read_file()时,GDAL会默认从本地磁盘路径查找文件,必然触发文件不存在的报错。 - Shapefile是多文件组合格式,读取
.shp必须依赖同目录下同名的.shx(索引文件)、.dbf(属性表)、.prj(坐标系)等附属文件,仅单独定位到.shp条目也无法完成正常读取。
修改方案
利用GDAL原生支持的/vsizip/虚拟文件系统协议,可以直接读取多层嵌套ZIP内的空间数据,全程不需要解压任何文件到本地磁盘,同时GDAL会自动匹配shapefile所需的所有附属文件。
修改后的完整代码如下,会自动检索所有符合命名规则的shapefile并合并为单个GeoDataFrame:
import zipfile from io import BytesIO import geopandas as gpd import pandas as pd # 存储所有读取到的目标图层 gdf_collect = [] with zipfile.ZipFile("Polska_SHP.zip", "r") as main_zip: # 遍历主压缩包内的二级zip for l1_entry in main_zip.namelist(): if not l1_entry.endswith(".zip"): continue l2_buffer = BytesIO(main_zip.read(l1_entry)) with zipfile.ZipFile(l2_buffer) as l2_zip: # 遍历二级zip内的三级zip for l2_entry in l2_zip.namelist(): if not l2_entry.endswith(".zip"): continue l3_buffer = BytesIO(l2_zip.read(l2_entry)) with zipfile.ZipFile(l3_buffer) as l3_zip: # 遍历三级zip内的所有文件,匹配目标shp for l3_entry in l3_zip.namelist(): if "SWRS" in l3_entry and l3_entry.endswith(".shp"): # 构造三层嵌套zip的GDAL虚拟读取路径 vsi_path = f"/vsizip//vsizip//vsizip/Polska_SHP.zip/{l1_entry}/{l2_entry}/{l3_entry}" print(f"已匹配到目标文件,正在读取: {l3_entry}") tmp_gdf = gpd.read_file(vsi_path) gdf_collect.append(tmp_gdf) # 合并所有图层,统一坐标系 final_gdf = gpd.GeoDataFrame( pd.concat(gdf_collect, ignore_index=True), crs=gdf_collect[0].crs ) # 如需导出到本地可取消下方注释 # final_gdf.to_file("merged_SWRS_polska.gpkg", driver="GPKG", encoding="utf-8")
注意事项
- 代码中三层
/vsizip/前缀对应三层ZIP嵌套结构,GDAL会自动解析内存中的嵌套压缩内容,不需要手动释放BytesIO对象,with代码块结束后会自动回收内存。 - 采用列表收集单个图层后一次性拼接的方式,比循环中逐次拼接GeoDataFrame的性能高很多,适合处理大量shapefile的合并场景。
- 如果运行时提示虚拟路径相关错误,可以检查fiona/GDAL版本,升级到fiona>=1.8、GDAL>=3.0即可正常支持多层嵌套ZIP读取。
内容的提问来源于stack exchange,提问作者Gosia Korona
相关产品推荐
相关产品推荐

