PostGIS导入Shapefile?常用命令是什么?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

很多同学在把矢量数据入库时,第一反应就是搜索“PostGIS导入Shapefile?常用命令是什么?”。这篇文章只解决一个具体问题:如何用常见命令把 Shapefile 稳定导入 PostgreSQL/PostGIS,并知道每个关键参数什么时候该用。

PostGIS导入Shapefile常用命令和shp2pgsql导入流程
Shapefile 导入 PostGIS 的典型流程:检查坐标系、编码和表名,再使用命令行工具入库。

引言:PostGIS导入Shapefile最常用的是哪条命令

在 PostGIS 中导入 Shapefile,最常见的命令有两类:一类是 PostGIS 自带的 shp2pgsql,另一类是 GDAL 提供的 ogr2ogr。如果只是把一个本地 Shapefile 导入数据库,shp2pgsql 通常更直接;如果涉及格式转换、批处理、字段映射或多数据源,ogr2ogr 更灵活。

最常用的 shp2pgsql 命令格式如下:

shp2pgsql -I -s 4326 -W UTF-8 your_data.shp public.your_table | psql -h localhost -p 5432 -U postgres -d gisdb

这条命令的含义是:读取 your_data.shp,指定坐标系 SRID 为 4326,按 UTF-8 读取属性编码,导入到 gisdb 数据库的 public.your_table 表中,并自动创建空间索引。

背景:为什么PostGIS导入Shapefile经常出错

Shapefile 是 GIS 中非常常见的矢量数据格式,但它并不是一个单文件格式。一个完整的 Shapefile 通常至少包含以下文件:

  • .shp:几何图形文件,存储点、线、面坐标。
  • .shx:几何索引文件。
  • .dbf:属性表文件。
  • .prj:坐标系定义文件,可能缺失或不规范。
  • .cpg:字符编码文件,常用于说明属性字段编码。

PostGIS导入Shapefile失败,常见原因不是命令本身复杂,而是数据源存在以下问题:

  • Shapefile 缺少 .prj,无法确认坐标系。
  • 中文字段或中文属性乱码,编码参数设置错误。
  • 表名、字段名包含中文、空格、特殊符号或过长。
  • 几何类型混杂,例如面图层里混入 MultiPolygon 或无效几何。
  • 目标数据库没有启用 PostGIS 扩展。
  • Windows 命令行路径包含空格,但没有加引号。

因此,正确的入库流程不是直接复制一条命令,而是先确认坐标系、编码、目标库和目标表结构。

原理:shp2pgsql命令到底做了什么

shp2pgsql 并不是直接把 Shapefile 写进数据库。它的工作原理是把 Shapefile 转换成一段 SQL 语句,然后再交给 psql 执行。

例如下面这条命令:

shp2pgsql -I -s 4490 -W GBK data/county.shp public.county | psql -U postgres -d gisdb

可以理解为两个步骤:

  1. shp2pgsql 读取 county.shp,生成创建表、插入属性和几何、创建空间索引的 SQL。
  2. psql 连接 PostgreSQL 数据库,把这些 SQL 执行到 gisdb 中。

PostGIS 中的空间数据会存储在 geometrygeography 字段中。Shapefile 导入时通常使用 geometry 字段。SRID 是空间参考系统编号,例如 4326 代表 WGS 84,经纬度坐标;4490 代表 CGCS2000 地理坐标系;常见 Web 墨卡托为 3857

需要注意:-s 参数只是告诉 PostGIS 这个数据的坐标系编号,并不一定执行坐标转换。如果原始 Shapefile 是 CGCS2000,却错误指定为 4326,数据可能看起来位置接近,但坐标系元数据已经错了。

步骤:使用shp2pgsql导入Shapefile到PostGIS

步骤1:确认数据库已经启用PostGIS扩展

先进入 PostgreSQL 数据库,确认目标数据库已经安装 PostGIS 扩展:

psql -h localhost -p 5432 -U postgres -d gisdb

进入数据库后执行:

CREATE EXTENSION IF NOT EXISTS postgis;

检查 PostGIS 是否可用:

SELECT postgis_full_version();

如果能返回 PostGIS 版本信息,说明数据库具备存储和查询空间数据的能力。

步骤2:确认Shapefile文件完整

在导入前,至少确认同一目录下存在这些文件:

county.shp
county.shx
county.dbf
county.prj

如果缺少 .shx.dbf,导入通常会失败。如果缺少 .prj,仍然可能导入,但需要你自己确认 SRID,否则后续叠加分析、距离计算、WebGIS 显示都容易出错。

步骤3:确认坐标系SRID

可以用 QGIS 打开 Shapefile,右键图层选择属性,查看源坐标参考系。也可以使用 GDAL 命令检查:

ogrinfo -al -so county.shp

如果数据是 WGS 84,经常使用:

-s 4326

如果数据是 CGCS2000,经常使用:

-s 4490

如果数据是 Web Mercator,经常使用:

-s 3857

如果是投影坐标系,例如高斯克吕格、UTM 或地方坐标系,需要根据 .prj 或数据提供方说明确定准确 EPSG 编号。

步骤4:执行最常用的shp2pgsql导入命令

假设数据库名为 gisdb,用户名为 postgres,Shapefile 为 county.shp,目标表为 public.county,坐标系为 4490,可以执行:

shp2pgsql -I -s 4490 -W UTF-8 county.shp public.county | psql -h localhost -p 5432 -U postgres -d gisdb

常用参数解释如下:

参数 作用 使用建议
-I 导入后创建 GiST 空间索引 建议保留,后续空间查询更快
-s 4490 指定几何字段的 SRID 必须与原始数据真实坐标系一致
-W UTF-8 指定属性表字符编码 中文乱码时重点检查
county.shp 输入 Shapefile 路径 路径有空格时加引号
public.county 目标 schema 和表名 建议使用英文小写和下划线
psql -d gisdb 连接目标数据库并执行 SQL 确认数据库名、用户、端口正确

步骤5:如果中文乱码,改用GBK或GB18030

国内很多历史 Shapefile 的属性表编码是 GBK 或 GB18030。如果导入后中文变成乱码,可以尝试:

shp2pgsql -I -s 4490 -W GBK county.shp public.county | psql -h localhost -p 5432 -U postgres -d gisdb

或者:

shp2pgsql -I -s 4490 -W GB18030 county.shp public.county | psql -h localhost -p 5432 -U postgres -d gisdb

如果 Shapefile 旁边存在 .cpg 文件,可以先打开查看里面写的是 UTF-8GBK936 还是其他编码。936 通常可按 GBK 处理。

步骤6:导入后检查表和几何字段

导入完成后,不要马上认为成功。建议执行以下检查:

SELECT COUNT(*) FROM public.county;

检查 SRID:

SELECT ST_SRID(geom) AS srid, COUNT(*)
FROM public.county
GROUP BY ST_SRID(geom);

检查几何类型:

SELECT GeometryType(geom) AS geom_type, COUNT(*)
FROM public.county
GROUP BY GeometryType(geom);

检查空间范围:

SELECT ST_Extent(geom) FROM public.county;

如果是经纬度数据,范围通常应接近经度、纬度数值,例如中国区域经度大致在 70 到 140,纬度大致在 15 到 55。若出现几百万的坐标值,说明它可能是投影坐标系,不应简单指定为 4326

步骤7:如果需要追加数据,使用-a参数

如果目标表已经存在,只想把同结构的新 Shapefile 追加进去,可以使用 -a

shp2pgsql -a -s 4490 -W UTF-8 county_part2.shp public.county | psql -h localhost -p 5432 -U postgres -d gisdb

注意,追加数据要求字段结构和几何类型基本一致。如果字段名不一致或字段类型冲突,可能会导入失败。

步骤8:如果需要删除旧表重建,使用-d参数

如果目标表已经存在,希望先删除再重新导入,可以使用 -d

shp2pgsql -d -I -s 4490 -W UTF-8 county.shp public.county | psql -h localhost -p 5432 -U postgres -d gisdb

注意:-d 会删除同名表。生产数据库中使用前必须确认是否有其他业务依赖该表。

步骤:使用ogr2ogr导入Shapefile到PostGIS

除了 shp2pgsqlogr2ogr 也是 PostGIS导入Shapefile 的常用命令。它适合需要转换格式、重投影、覆盖图层、指定几何字段名的场景。

基本命令如下:

ogr2ogr -f "PostgreSQL" PG:"host=localhost port=5432 dbname=gisdb user=postgres password=your_password" county.shp -nln public.county -lco GEOMETRY_NAME=geom -lco FID=gid -lco SPATIAL_INDEX=GIST

如果要在导入时指定或转换坐标系,可以使用:

ogr2ogr -f "PostgreSQL" PG:"host=localhost port=5432 dbname=gisdb user=postgres password=your_password" county.shp -nln public.county -a_srs EPSG:4490

-a_srs 是指定数据坐标系,不做坐标转换。如果要真正重投影,应使用 -t_srs

ogr2ogr -f "PostgreSQL" PG:"host=localhost port=5432 dbname=gisdb user=postgres password=your_password" county.shp -nln public.county_4326 -t_srs EPSG:4326

如果原始数据坐标系信息缺失,但你确认它是 CGCS2000,并希望转换到 WGS 84,可以组合使用:

ogr2ogr -f "PostgreSQL" PG:"host=localhost port=5432 dbname=gisdb user=postgres password=your_password" county.shp -nln public.county_4326 -s_srs EPSG:4490 -t_srs EPSG:4326

常见坑:PostGIS导入Shapefile失败时优先检查这些问题

坑1:把指定SRID误认为坐标转换

shp2pgsql -s 4326 主要是给几何字段写入 SRID。它不会自动把高斯投影坐标转换成经纬度。如果需要转换坐标系,可以先用 QGIS 另存为目标 CRS,或用 ogr2ogr -t_srs 重投影。

坑2:中文乱码只改数据库编码还不够

PostgreSQL 数据库通常建议使用 UTF-8,但 Shapefile 的 .dbf 可能是 GBK。PostGIS导入Shapefile中文乱码时,重点检查 -W 参数,而不是只改数据库编码。

坑3:表名和字段名不规范

Shapefile 字段名有长度限制,且历史数据中常见中文字段、括号、空格。导入数据库后,建议统一使用英文小写字段名,例如 namecodeareatype。如果是正式项目,最好先在 QGIS、ArcGIS Pro 或 Python 中整理字段。

坑4:Windows路径没有加引号

如果路径中包含空格,例如:

D:GIS Datacounty.shp

命令中应写成:

"D:GIS Datacounty.shp"

否则命令行会把路径拆开,导致找不到文件。

坑5:目标数据库没有postgis扩展

如果出现 geometry 类型不存在、函数不存在等错误,通常是目标数据库没有执行:

CREATE EXTENSION postgis;

注意,PostGIS 扩展是按数据库启用的,不是只在 PostgreSQL 实例上安装一次就所有库都自动可用。

坑6:几何无效导致后续分析失败

有些 Shapefile 可以成功导入,但后续做叠加、裁剪、相交查询时报错。这通常与无效几何有关。可以检查:

SELECT COUNT(*)
FROM public.county
WHERE NOT ST_IsValid(geom);

如果存在无效几何,可尝试:

UPDATE public.county
SET geom = ST_MakeValid(geom)
WHERE NOT ST_IsValid(geom);

ST_MakeValid 可能改变几何类型,例如 Polygon 变成 MultiPolygon 或 GeometryCollection,正式处理前应抽样检查结果。

方法比较:shp2pgsql和ogr2ogr该选哪个

对比项 shp2pgsql ogr2ogr
适合场景 单个 Shapefile 快速导入 PostGIS 多格式转换、重投影、批处理、复杂导入
学习成本 较低,参数相对集中 稍高,参数体系更大
坐标转换 主要指定 SRID,不适合直接重投影 支持 -s_srs-t_srs 重投影
编码处理 常用 -W 指定编码 可结合 GDAL 配置和图层选项处理
空间索引 -I 创建 GiST 索引 -lco SPATIAL_INDEX=GIST 创建索引
推荐用法 日常入库首选 数据转换和自动化流程首选

简单判断:如果你只是问 PostGIS导入Shapefile常用命令是什么,优先掌握 shp2pgsql;如果你还需要重投影、转换 GeoJSON、批量处理目录中的数据,再学习 ogr2ogr

检查清单:导入前后逐项确认

  • 确认目标数据库已执行 CREATE EXTENSION postgis;
  • 确认 Shapefile 至少包含 .shp.shx.dbf
  • 确认 .prj 是否存在,并核对真实坐标系。
  • 确认 SRID 参数正确,例如 432644903857
  • 确认中文属性编码,必要时尝试 -W UTF-8-W GBK-W GB18030
  • 确认目标表名使用英文小写和下划线。
  • 导入后执行 COUNT(*) 检查记录数。
  • 导入后执行 ST_SRID 检查坐标系编号。
  • 导入后执行 ST_Extent 检查空间范围是否合理。
  • 导入后检查是否存在无效几何。
  • 正式库中谨慎使用 -d 删除重建表。

FAQ:PostGIS导入Shapefile常见问题

PostGIS导入Shapefile最常用命令是什么?

最常用的是:

shp2pgsql -I -s 4326 -W UTF-8 data.shp public.data | psql -h localhost -p 5432 -U postgres -d gisdb

其中 -I 表示创建空间索引,-s 表示指定 SRID,-W 表示指定属性编码。

shp2pgsql导入Shapefile时-s参数必须写吗?

建议写。-s 用于设置几何字段的 SRID。没有正确 SRID 的空间表,在后续空间分析、距离计算、坐标转换和 WebGIS 发布时很容易出问题。

PostGIS导入Shapefile中文乱码怎么办?

优先检查 Shapefile 的属性编码。常见解决方式是把 -W UTF-8 改为 -W GBK-W GB18030。如果有 .cpg 文件,可以先查看其编码声明。

shp2pgsql能把投影坐标转换成经纬度吗?

一般不建议用 shp2pgsql 做坐标转换。-s 主要用于指定 SRID。需要真正重投影时,建议使用 QGIS 另存为目标坐标系,或使用 ogr2ogr -t_srs EPSG:4326

导入后为什么在地图上位置不对?

常见原因是 SRID 写错、原始 Shapefile 的 .prj 不准确、投影坐标被当成经纬度、或 WebGIS 前端没有正确处理坐标系。可以先用 ST_SRIDST_Extent 检查数据库中的坐标范围。

PostGIS导入Shapefile需要创建空间索引吗?

建议创建。空间索引能明显改善 ST_IntersectsST_WithinST_DWithin 等空间查询的性能。使用 shp2pgsql 时加 -I 即可创建 GiST 空间索引。

已经有同名表时怎么办?

如果要追加数据,使用 -a;如果要删除旧表并重建,使用 -d;如果不确定旧表是否还有用,不要直接使用 -d。生产环境中建议先备份表或导入到临时表。

可以批量导入多个Shapefile吗?

可以。Windows 可以写批处理脚本,Linux 或 macOS 可以写 shell 脚本。批量导入时要特别注意每个 Shapefile 的坐标系、编码和表名是否一致,不要为了省事给所有数据套同一个 SRID。

结论:先掌握shp2pgsql,再根据场景使用ogr2ogr

PostGIS导入Shapefile的核心命令并不复杂,日常最常用的是 shp2pgsql -I -s SRID -W 编码 文件.shp schema.表名 | psql ...。真正容易出问题的是坐标系、中文编码、表名字段名、空间索引和无效几何。

如果你的目标是快速把 Shapefile 入库,优先使用 shp2pgsql;如果你需要重投影、格式转换或构建自动化数据处理流程,再使用 ogr2ogr。无论使用哪种方法,导入后都应检查记录数、SRID、几何类型和空间范围,这样才能保证 PostGIS 中的数据可查询、可分析、可发布。