☰
GeoPandas 输入输出(I/O)全指南:read_file、PostGIS、Feather 与 Parquet 实战详解
2026/10/14 16:18:27 网站建设 项目流程
  • 数据分析
  • GIS

【免费下载链接】geopandas

Python tools for geographic data

项目地址:https://gitcode.com/gh_mirrors/ge/geopandas
点击查看免费下载

导读

本文以 GeoPandas 官方 API 参考手册中 Input/output 索引页 为骨架,系统讲解 GeoPandas 数据读写体系的四大板块:GIS 矢量文件读写、PostGIS 空间数据库读写、Apache Parquet 与 Feather 二进制格式的快速往返。读完本文,你将掌握read_file/to_file的参数细节与引擎切换机制、PostGIS 的 SRID 与几何类型推导逻辑、GeoParquet 元数据与编码选项,并能在实际项目中按需选择最合适的读写方案。

一、API 全景:四大读写通道

GeoPandas 的 I/O 功能通过geopandas.io模块实现,公开函数在 geopandas/init.py 中统一注册为顶层 API,并全部以GeoDataFrame的实例方法形式暴露。官方参考文档将其划分为四组:

分类读取函数写入方法底层依赖
GIS 矢量文件read_file、read_file_info、list_layersGeoDataFrame.to_filepyogrio / fiona(GDAL)
PostGIS 数据库read_postgisGeoDataFrame.to_postgisSQLAlchemy + GeoAlchemy2 + psycopg
Featherread_featherGeoDataFrame.to_featherpyarrow >= 0.17
Parquetread_parquetGeoDataFrame.to_parquetpyarrow

这四组通道覆盖了从本地文件、URL、压缩包、对象存储到空间数据库的全部常见数据源,是 GeoPandas 日常数据处理的基础设施。

二、GIS 矢量文件读写:read_file 与 to_file

2.1 read_file:一网打尽矢量格式

geopandas.read_file(filename)是使用最频繁的入口,几乎可以读取 GDAL/OGR 支持的任何矢量格式(ESRI Shapefile、GeoJSON、GeoPackage、GML、GPX、FlatGeobuf 等)。它的核心实现在 geopandas/io/file.py。

参数速查表(来自_read_file的 docstring 与实现):

参数类型/默认值说明
filenamestr / pathlib.Path / file-like文件路径、URL,或任何带read()方法的对象(如打开的文件句柄、StringIO、BytesIO)
bboxtuple(minx, miny, maxx, maxy)/ GeoDataFrame / GeoSeries / shapely Geometry仅加载与包围盒相交的要素;不能与mask同时使用
maskdict / GeoDataFrame / GeoSeries / shapely Geometry仅加载与给定几何相交的要素;多几何时先做 union,可能开销较大
columnslist只读取指定列(列名必须与数据源完全一致);传空 list 可跳过所有属性列
rowsint 或 slice只加载前 N 行或切片范围内的行
engine"pyogrio"或"fiona"底层读取库,见下文引擎机制
**kwargs透传传给pyogrio.read_dataframe或fiona.open

支持的输入形态:

  • 路径对象:直接传pathlib.Path(源码 会先做~展开);
  • URL:_read_file会先探测服务器是否支持 Range 请求(随机访问),支持则把 URL 原样传给引擎让 GDAL 通过网络文件系统流式读取;不支持则先整体下载再传入内存(源码);
  • ZIP 包:使用 GDAL 虚拟文件系统语法,如"zip:///path/to/file.zip"或带内部路径的"zip:///file.zip!data/layer.shp";
  • file-like 对象:文件句柄、io.StringIO/BytesIO、fsspec 打开的流均可,fiona 引擎会读取其内容转换为字节流处理。
import geopandas # 最基本用法 df = geopandas.read_file("nybb.shp") # 多图层文件指定 layer countries = geopandas.read_file("package.gpkg", layer="countries") # 只读前 10 行 df = geopandas.read_file("nybb.shp", rows=10) # 按包围盒过滤 df = geopandas.read_file("nybb.shp", bbox=(0, 0, 10, 20)) # 按几何 mask 过滤 df = geopandas.read_file("nybb.shp", mask=polygon) # 只读取部分字段(pyogrio 或 Fiona 1.9+) df = geopandas.read_file("nyc.gpkg", columns=["name", "rent2008"]) # 跳过几何列,返回纯 pandas.DataFrame pdf = geopandas.read_file("nyc.gpkg", ignore_geometry=True) # 用 SQL WHERE 子句过滤(Fiona 1.9+ 或 pyogrio) df = geopandas.read_file("nyc.gpkg", where="subborough='Coney Island'") # 将 GPKG 的 fid 作为索引(pyogrio 引擎) df = geopandas.read_file("columbus.gpkg", fid_as_index=True)

引擎机制:这是 GeoPandas 的一个关键设计。_check_engine(geopandas/io/file.py#L123-L154)的判定顺序为:显式传入的engine参数 > 全局选项geopandas.options.io_engine> 自动探测(优先 pyogrio,其次 fiona)。两引擎对同一批参数的处理存在差异,从源码可归纳出:

  • bbox 的 CRS 处理:fiona 引擎若传入 GeoSeries/GeoDataFrame 会先转换 CRS 对齐;pyogrio 引擎要求 bbox 与数据集同一 CRS(源码 中会读取数据集 CRS 后对 GeoSeries 做to_crs);
  • rows 的 slice 支持:pyogrio 引擎支持rows=10与rows=slice(10, 20),但不支持带 step 的切片,也不支持负索引(源码);
  • 编码处理:_read_file_fiona对 datetime 字段做毫秒级截断处理(fiona 精度限制,源码)。

加速读取:使用默认 pyogrio 引擎时,传use_arrow=True可将读取速度提升约 2–4 倍(需要环境中安装 pyarrow),也可通过环境变量PYOGRIO_USE_ARROW=1全局开启。

2.2 list_layers 与 read_file_info:图层探测

对于多图层文件(GeoPackage 等),可用两个辅助函数先行探测:

  • geopandas.list_layers(filename):返回一个含name与geometry_type两列的DataFrame,每行对应一个图层;非空间图层(如属性表)的geometry_type为None(实现见 geopandas/io/file.py#L873-L901);
  • geopandas.read_file_info(filename, layer=None):返回指定图层(默认第一层)的元数据字典,包含字段名、几何类型、CRS 等信息(实现见 geopandas/io/file.py#L904-L929)。

两者都直接包装pyogrio.list_layers与pyogrio.read_info,因此仅在使用 pyogrio 引擎时可用。

2.3 to_file:写出矢量文件

GeoDataFrame.to_file(filename, driver=None, ...)将数据写出到任意 OGR 支持的格式(公开方法定义,底层实现 geopandas/io/file.py#L620-L799)。

关键参数:

  • driver:默认None,从文件扩展名自动推断。内置映射表_EXTENSION_TO_DRIVER(geopandas/io/file.py#L157-L178)覆盖.shp/.dbf → ESRI Shapefile、.geojson/.json → GeoJSON、.gpkg → GPKG、.gml/.xml → GML、.fgb → FlatGeobuf等;无扩展名时按 Shapefile 文件夹处理;
  • schema:fiona 引擎可传 schema 字典精细控制写出结构;pyogrio 引擎不支持(会抛ValueError,源码);
  • index:默认None,仅当索引有名字、是 MultiIndex 或非整数 dtype 时才写出;True/False强制写出或不写出;
  • mode:'w'覆盖、'a'追加(并非所有 driver 支持追加;pyogrio 引擎对应append=True参数);
  • crs:fiona 引擎可显式指定 CRS(GDAL 3.0+ 时写 WKT 而非 WKT1_GDAL,源码);pyogrio 引擎不支持传 crs,一律使用 GeoDataFrame 自带的df.crs;
  • metadata:dict[str, str],仅 GPKG driver 支持写入文件元数据(要求 Fiona >= 1.9 或 pyogrio >= 0.6,校验逻辑见 geopandas/io/file.py#L109-L121)。

写出时的数据约束(来自 geopandas/io/file.py#L716-L730 与用户指南):

  • 列名超过 10 字符写 Shapefile 会被截断(发出警告);
  • 包含多个 geometry 列时直接抛错——建议先用GeoSeries.to_wkt()/to_wkb()转换非活动几何列,或改用 Parquet/Feather(原生支持多几何列);
  • GeoDataFrame 中的 Python 对象列(如 tuple、list)无法直接写入大部分格式,需先转换。
# 写 Shapefile(默认推断 driver) countries_gdf.to_file("countries.shp") # 显式指定 GeoJSON driver countries_gdf.to_file("countries.geojson", driver="GeoJSON") # 多图层写 GeoPackage countries_gdf.to_file("package.gpkg", layer="countries", driver="GPKG") cities_gdf.to_file("package.gpkg", layer="cities", driver="GPKG") # 多几何列处理:非活动几何列转 WKT 后再写 countries_gdf["country_center"] = countries_gdf["geometry"].centroid countries_gdf["country_center"] = countries_gdf["country_center"].to_wkt() countries_gdf.to_file("countries.geojson", driver="GeoJSON") # pyogrio 引擎下加速写出 countries_gdf.to_file("countries.shp", use_arrow=True)

schema 推断细节:fiona 引擎在未显式传schema时调用infer_schema(geopandas/io/file.py#L802-L850):object/string 类型映射为str、datetime 映射为datetime、Int32/Int64/boolean 有专门映射;几何类型通过_geometry_types区分 2D/3D("3D "前缀)与混合类型,空数据默认"Unknown"。写空 DataFrame 时会发出警告,因为部分 driver 可能失败。

三、PostGIS 数据库读写

3.1 read_postgis:从空间数据库取数

geopandas.read_postgis(sql, con, geom_col="geom", crs=None, ...)返回GeoDataFrame,核心实现在 geopandas/io/sql.py#L126-L209。它的工作方式是:用pandas.read_sql执行查询,再把查询结果中的 WKB 几何列转换为 shapely 几何(shapely.wkb.loads,自动识别 bytes 与 hex 文本两种形式),最后包装为GeoDataFrame。

参数要点:

  • sql:SQL 查询字符串或表名,查询结果必须包含一个 WKB 表示的几何列;
  • con:SQLAlchemyEngine或Connection;
  • geom_col:几何列名,默认"geom";
  • crs:可显式指定;不指定时从数据库返回的首个几何的 SRID 自动推导——优先查询spatial_ref_sys表得到权威 CRS 名(如EPSG:4326),表缺失或查不到时回退为epsg:<srid>并发出警告(源码);
  • chunksize:设置后返回生成器,每次产出指定行数的GeoDataFrame(分块读取大结果集);
  • 其余index_col、coerce_float、parse_dates、params与pandas.read_sql语义一致。
from sqlalchemy import create_engine db_connection_url = "postgresql://myusername:mypassword@myhost:5432/mydatabase" con = create_engine(db_connection_url) # PostGIS:直接取含 geometry 的列 sql = "SELECT geom, highway FROM roads" df = geopandas.read_postgis(sql, con) # SpatiaLite:需要显式转 WKB sql = "SELECT ST_AsBinary(geom) AS geom, highway FROM roads" df = geopandas.read_postgis(sql, con)

3.2 to_postgis:上传到 PostGIS

GeoDataFrame.to_postgis(name, con, schema=None, if_exists="fail", index=False, index_label=None, chunksize=None, dtype=None)需要 SQLAlchemy、GeoAlchemy2 和 psycopg/psycopg2,底层实现在 geopandas/io/sql.py#L343-L460。

写入流程(从源码还原的调用链):

  1. SRID 提取:_get_srid_from_crs(geopandas/io/sql.py#L259-L286)按置信度 100 → 70 → 25 依次尝试to_epsg,再尝试 ESRI 权威码;全部失败则 SRID 记为 0(未定义 CRS)并警告;
  2. 几何类型推导:_get_geometry_type(geopandas/io/sql.py#L212-L256)——所有几何同型则用该类型(LinearRing 转为 LineString);混合类型或含 GeometryCollection 时降级为GEOMETRY;任一几何含 Z 坐标则整体加Z后缀;
  3. EWKB 转换:_convert_to_ewkb用shapely.to_wkb(include_srid=True)把几何序列化为带 SRID 的 EWKB;
  4. 写入:通过pandas.DataFrame.to_sql配合自定义的_psql_insert_copy(geopandas/io/sql.py#L316-L340)方法——用COPY ... FROM STDIN WITH CSV批量灌入,psycopg3 走cursor.copy(),psycopg2 走copy_expert(),比逐行 INSERT 快得多;
  5. append 校验:if_exists="append"时先查目标表的Find_SRID,若与当前 GeoDataFrame 的 SRID 不一致直接抛ValueError,避免几何语义错乱。
from sqlalchemy import create_engine engine = create_engine("postgresql://myusername:mypassword@myhost:5432/mydatabase") countries_gdf.to_postgis("countries_table", con=engine) # 追加时 SRID 必须一致 countries_gdf.to_postgis("countries_table", con=engine, if_exists="append")

if_exists取值'fail'(默认,表已存在抛 ValueError)、'replace'(先删表再写入)、'append'(追加数据)。schema默认"public"。

四、Apache Parquet 与 Feather:二进制快速往返

4.1 格式背景

Parquet 是 Hadoop 生态起源的高效列式存储格式,Feather 是 Apache Arrow 内存格式的磁盘表示。两者都基于列式存储,特别适合大数据分析与数据湖场景。GeoPandas 自 0.8 起支持这两种格式,写入文件时遵循 GeoParquet 规范:geo.columns.<name>记录每个几何列的encoding(WKB / geoarrow)、geometry_types、crs(PROJJSON)、bbox、covering等信息,primary_column标记主几何列,version标记规范版本,creator记录写入方(geopandas 及版本号)。

4.2 写入:to_parquet 与 to_feather

两个方法的完整签名与说明在 geodataframe.py#L1436-L1570,底层实现_to_parquet/_to_feather在 geopandas/io/arrow.py#L462-L567。

参数to_parquetto_feather
indexTrue/False/None;None时 RangeIndex 只存元数据,其余写为列同左
compression'snappy'(默认)、'gzip'、'brotli'、'lz4'、'zstd'、None'zstd'、'lz4'、'uncompressed'(默认 LZ4 可用则用 LZ4,否则不压缩)
geometry_encoding'WKB'(默认,互操作性最好)或'geoarrow'(GeoParquet 1.1 实验性原生编码)固定 WKB
write_covering_bbox默认False;开启后每行写bbox列,支持read_parquet的 bbox 过滤读取(计算开销较大,仅 GeoParquet 1.1.0+ 支持)不支持
schema_version'0.1.0'/'0.4.0'/'1.0.0'/'1.1.0'/'2.0.0',默认最新稳定版 1.1.0'0.1.0'–'1.1.0',默认 1.1.0
额外 kwargs传给pyarrow.parquet.write_table传给pyarrow.feather.write_feather

需要注意的约束(从 geopandas/io/arrow.py#L178-L183 可确认):写 GeoParquet 2.0.0 时仅支持 WKB 编码,要用geoarrow编码需显式指定schema_version='1.1.0'。另外to_parquet只接受engine='auto'或'pyarrow'(与 pandas API 兼容性处理,源码)。

gdf.to_parquet("data.parquet") # 默认 snappy + WKB gdf.to_parquet("data.parquet", compression="zstd") gdf.to_parquet("data.parquet", geometry_encoding="geoarrow", schema_version="1.1.0") gdf.to_parquet("data.parquet", write_covering_bbox=True) # 便于后续 bbox 过滤 gdf.to_feather("data.feather") gdf.to_feather("data.feather", compression="zstd")

4.3 读取:read_parquet 与 read_feather

两个读取函数共享_arrow_to_geopandas主逻辑(geopandas/io/arrow.py#L570-L611),支持从路径、file-like 对象和带://的远程地址(fsspec/pyarrow.fs,含 S3、GCS 等)读取。

参数要点:

  • columns:列子集。若读出的列里没有任何几何列则抛ValueError(提示改用pandas.read_parquet);若主几何列不在其中,会把第一个读到的几何列提升为返回 GeoDataFrame 的活动几何列(多几何列时发出警告);
  • bbox:仅当文件写入了 covering bbox 元数据(或 GeoParquet >= 2.0)时可用;(xmin, ymin, xmax, ymax)四元组。实现上优先把 bbox 转成 pyarrow 过滤表达式在行组层面裁剪,无 bbox 列时退化为行组级手动过滤 + 行级后过滤(源码),以保证语义一致;
  • storage_options:HTTP(S) URL 转发给 urllib,s3://、gcs://等转发给 fsspec;不传时若 pyarrow.fs 与 fsspec 都实现了某文件系统,优先用 pyarrow.fs;
  • to_pandas_kwargs:控制非几何列转 pandas 的行为(如 dtype 转换);
  • 其余 kwargs 透传给pyarrow.parquet.read_table/read_feather(如filters谓词下推,会与 bbox 过滤用&拼接)。

兼容性:读取支持 GeoParquet 0.1.0、0.4.0、1.0.0、1.1.0、2.0.0 全部版本;若元数据缺少crs键,按规范默认"OGC:CRS84"。

gdf = geopandas.read_parquet("data.parquet") gdf = geopandas.read_parquet("data.parquet", columns=["geometry", "pop_est"]) # 基于 covering bbox 的过滤读取 gdf = geopandas.read_parquet("data.parquet", bbox=(100, 40, 110, 50)) # 从字节流读取 with BytesIO(p_data) as geo_bytes: gdf = geopandas.read_parquet(geo_bytes) gdf = geopandas.read_feather("data.feather")

Parquet 与 Feather 相比矢量文件格式的最大优势:原生支持多个几何列(矢量格式通常只支持一个活动几何列)、保留完整 CRS 信息、读写速度极快、天然适配 Arrow 生态的数据分析链路。

五、底层原理与实现佐证

5.1 模块组织与公开 API 注册

geopandas.io内部按数据源拆分为三个模块:file.py(矢量文件)、sql.py(数据库)、arrow.py(Parquet/Feather)。顶层 geopandas/init.py 中通过别名导入暴露公共函数(如from geopandas.io.file import _read_file as read_file),同时这些函数以方法形式绑定在GeoDataFrame上。测试方面,geopandas/io/tests/test_file.py 覆盖了 bbox/rows 过滤、URL 读取、file-like 对象、datetime 精度、Z 坐标写出、重复列检测等行为,可作为参数边界的权威参考。

5.2 两个容易踩坑的差异点

  • fiona 与 pyogrio 的参数不对称:schema、crs仅 fiona 引擎支持;fid_as_index、use_arrow仅 pyogrio 支持;metadata两者都要求 GPKG driver。跨引擎迁移代码时需先确认geopandas.options.io_engine的取值;
  • write 前请检查列与几何:写 Shapefile 前列名超过 10 字符会被截断;多几何列、重复列名(pyogrio 引擎直接抛错)、非标量对象列都会导致写出失败——这些校验逻辑集中在 geopandas/io/file.py#L716-L730 与 geopandas/io/file.py#L795-L797。

六、选型建议

场景推荐方案理由
读取/写出各类标准 GIS 格式(shp、GeoJSON、GPKG、GML)read_file/to_file覆盖最全,自动推断 driver
多图层文件(如 GeoPackage)list_layers+read_file(layer=...)先探测再定向读取
与 PostGIS 数据库交互read_postgis/to_postgisSQL 灵活,SRID 自动推导,COPY 批量灌入
大数据分析、数据湖、多几何列往返read_parquet/to_parquet列式压缩存储、bbox 下推过滤、原生多几何列
快速落盘/加载、Arrow 生态内交换read_feather/to_feather读写开销最低
追求读取/写出极限速度各函数加use_arrow=True(pyogrio 引擎)官方文档说明可快 2–4 倍

以上 API 的全部签名与完整参数说明,还可直接查看官方参考页 docs/reference/io.rst 及其生成的 API 文档,并结合 用户指南 io 章节 获得更多带示例的实战讲解。

  • 数据分析
  • GIS

【免费下载链接】geopandas

Python tools for geographic data

项目地址:https://gitcode.com/gh_mirrors/ge/geopandas
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询