C# + NetTopologySuite读取Shp存入PostGIS数据库

之前文章中,我们下载了西安路网数据Shp。分享一个下载各省市边界、路网等数据的地址-CSDN博客

今天我们将Shp数据存入PostGIS空间数据库。

VS项目Nuget引入NetTopologySuite,NetTopologySuite.IO.Esri.Shapefile,NetTopologySuite.IO.PostGis库

<PackageReference Include="NetTopologySuite" Version="2.5.0" />
<PackageReference Include="NetTopologySuite.IO.Esri.Shapefile" Version="1.0.0" />
<PackageReference Include="NetTopologySuite.IO.PostGis" Version="2.1.0" />

创建一个model,用来存储路网数据中的属性数据和空间数据:

public class RoadModel
{
    public long OsmId { get; set; }

    public int RoadTypeCode { get; set; }

    public string RoadType { get; set; }

    public string RoadName { get; set; }

    public string RoadRef { get; set; }

    public string Oneway { get; set; }

    public int MaxSpeed { get; set; }

    public string Bridge { get; set; }

    public string Tunnel { get; set; }

    /// <summary>
    /// geometry: wkb
    /// </summary>
    public byte[] RoadShape { get; set; }
}

读取Shp文件的所有feature(涉及到Geometry,WKB的转换):

private const string roadShpFilePath = @"D:\workdata\xian\610100_new.shp";

private List<RoadModel> GetAttributesFromShapeFile()
{
    var features = NetTopologySuite.IO.Esri.Shapefile.ReadAllFeatures(roadShpFilePath);
    var pgWriter = new PostGisWriter();
    var roadModels = new List<RoadModel>();

    foreach (var feature in features)
    {
        //此时通过NTS库读取的Geometry SRID为0,没有坐标系
        var geometry = feature.Geometry;
        
        //这一步为Geometry添加4326坐标系
        var geometryForWGS84 = GeometryFactory.Default.WithSRID(4326).CreateGeometry(geometry);
        
        //如果这一步直接使用NTS库转换Geometry为WKB,此时得到的WKB还是没有坐标系的
        //var wkbForWGS84 = geometryForWGS84.ToBinary();
        
        //需要通过NTS PG库将含有坐标系的Geometry转成含有坐标系的EWKB
        var wkbForWGS84 = pgWriter.Write(geometryForWGS84);

        roadModels.Add(new RoadModel
        {
            OsmId = Convert.ToInt64(feature.Attributes.GetOptionalValue("osm_id")),
            RoadTypeCode = Convert.ToInt32(feature.Attributes.GetOptionalValue("code")),
            RoadType = feature.Attributes.GetOptionalValue("fclass").ToString(),
            RoadName = feature.Attributes.GetOptionalValue("name").ToString(),
            RoadRef = feature.Attributes.GetOptionalValue("ref").ToString(),
            Oneway = feature.Attributes.GetOptionalValue("oneway").ToString(),
            MaxSpeed = Convert.ToInt32(feature.Attributes.GetOptionalValue("maxspeed")),
            Bridge = feature.Attributes.GetOptionalValue("bridge").ToString(),
            Tunnel = feature.Attributes.GetOptionalValue("tunnel").ToString(),
            RoadShape = wkbForWGS84,
        });
    }
    return roadModels;
}

在PostGIS数据库中创建表road_xian并赋予坐标系:

CREATE TABLE public.road_xian (
	osm_id int8 NOT NULL,
	road_type_code int4 NULL,
	road_type varchar NULL,
	road_name varchar NULL,
	road_ref varchar NULL,
	oneway varchar NULL,
	max_speed int4 NULL,
	bridge varchar NULL,
	tunnel varchar NULL,
	shape public.geometry NULL,
	CONSTRAINT road_xian_pk PRIMARY KEY (osm_id)
);
--此时表的shape字段坐标系为0,所以执行下面这句sql为shape字段添加上4326 WGS84坐标系

SELECT UpdateGeometrySRID('road_xian','shape',4326);

PostGIS数据库的安装可参考之前的文章Linux 安装PostGIS 3.1-CSDN博客

VS项目Nuget再引入Npgsql,Npgsql.LegacyPostgis库:

<PackageReference Include="Npgsql" Version="8.0.1" />
<PackageReference Include="Npgsql.LegacyPostgis" Version="5.0.17" />

通过NpgsqlCommand将数据插入db,shape(Geometry)字段需要用DbType.Object类型:

private int InsertIntoPg(List<RoadModel> roadModels)
{
    var allNum = 0;
    var connString = "Host=192.168.137.133;Username=postgres;Password=postgres;Database=gis_lp";
    var connection = new NpgsqlConnection(connString);
    connection.Open();

    var sql = $"INSERT INTO road_xian (osm_id, road_type_code, road_type, road_name, road_ref, oneway, max_speed, bridge, tunnel, shape) " +
                                    $"VALUES (@osm_id, @road_type_code, @road_type, @road_name, @road_ref, @oneway, @max_speed, @bridge, @tunnel, @shape)";

    foreach (var model in roadModels)
    {
        using (var command = new NpgsqlCommand(sql, connection))
        {
            var parameters = ConstructParameters(model);
            command.Parameters.AddRange(parameters.ToArray());
            var num = command.ExecuteNonQuery();
            allNum += num;
        }
    }

    return allNum;
}

private List<NpgsqlParameter> ConstructParameters(RoadModel roadModel)
{
    var osmIdPar = new NpgsqlParameter("osm_id", NpgsqlDbType.Bigint)
    {
        Value = roadModel.OsmId
    };
    var roadTypeCodePar = new NpgsqlParameter("road_type_code", NpgsqlDbType.Integer)
    {
        Value = roadModel.RoadTypeCode
    };
    var roadTypePar = new NpgsqlParameter("road_type", NpgsqlDbType.Varchar)
    {
        Value = roadModel.RoadType
    };
    var roadNamePar = new NpgsqlParameter("road_name", NpgsqlDbType.Varchar)
    {
        Value = roadModel.RoadName
    };
    var roadRefPar = new NpgsqlParameter("road_ref", NpgsqlDbType.Varchar)
    {
        Value = roadModel.RoadRef
    };
    var onewayPar = new NpgsqlParameter("oneway", NpgsqlDbType.Varchar)
    {
        Value = roadModel.Oneway
    };
    var maxSpeedPar = new NpgsqlParameter("max_speed", NpgsqlDbType.Integer)
    {
        Value = roadModel.MaxSpeed
    };
    var bridgePar = new NpgsqlParameter("bridge", NpgsqlDbType.Varchar)
    {
        Value = roadModel.Bridge
    };
    var tunnelPar = new NpgsqlParameter("tunnel", NpgsqlDbType.Varchar)
    {
        Value = roadModel.Tunnel
    };
    var geoPar = new NpgsqlParameter("shape", DbType.Object)
    {
        Value = roadModel.RoadShape
    };
    return new List<NpgsqlParameter>
    {
        osmIdPar,roadTypeCodePar,roadTypePar,roadNamePar,roadRefPar,onewayPar,maxSpeedPar,bridgePar,tunnelPar,geoPar
    };
}

启动项目,大约18s后,29902条数据成功插入db。

 

打开QGIS,在左侧PostgreSQL建立新的连接:

 

选择我们刚才创建的road_xian表,添加到当前地图项目中预览,与之前下载的Shp数据重叠一致,数据OK!

 

 

 

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
你可以使用第三方读取和处理 Shapefile (shp) 文件。其中一个常用的是 DotSpatial,它提供了 C# 的 API 来读取和操作 Shapefile 数据。 首先,你需要在项目中引入 DotSpatial 。你可以通过 NuGet 包管理器来安装它,或者手动下载并添加到项目引用中。 安装完成后,你可以按照以下步骤来读取 Shapefile 文件: 1. 导入所需的命名空间: ```csharp using DotSpatial.Data; using DotSpatial.Topology; ``` 2. 创建一个 ShapefileFeatureProvider 对象并打开 Shapefile 文件: ```csharp ShapefileFeatureProvider shapefile = new ShapefileFeatureProvider("path_to_your_shapefile.shp"); shapefile.Open(); ``` 3. 通过 FeatureSet 属性获取 Shapefile 的要素集合: ```csharp IFeatureSet featureSet = shapefile.GetFeatureSet(); ``` 4. 遍历要素集合,处理每个要素的属性和几何形状: ```csharp foreach (IFeature feature in featureSet.Features) { IGeometry geometry = feature.Geometry; // 在这里处理几何形状 DataRow attributes = feature.DataRow; // 在这里处理属性数据 } ``` 5. 关闭 Shapefile 文件: ```csharp shapefile.Close(); ``` 上述代码中的 "path_to_your_shapefile.shp" 应替换为你实际的 Shapefile 文件路径。你也可以使用其他方法来读取和处理 Shapefile 文件,例如使用 OGR 或其他相关的。 请注意,读取 Shapefile 文件时,你可能还需要读取相关的 dbf、shx 和 prj 文件,这些文件包含了 Shapefile 的属性、索引和投影信息。你可以通过相同的方法来读取这些文件。 希望这能帮助到你!如果有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

biu啊biu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值