C#将shapefile转换为geojson—通过GDAL

最近项目上,后台需要将数据处理的结果返回geojson数据的格式,自己写的拼接geojson方法始终存在问题。面太复杂,各种内环外环,面的相交等,无法完美解析,就采用这个办法,直接通过gdal,将结果转换为geojson,再返回,用别人造好的轮子,结实耐用。

一、下载

下载链接:http://www.gisinternals.com/release.php

这是我下载的版本

 

 解压后找到如下几个文件

 

 

二、环境搭建

项目中引用上面8个dll中带csharp后缀的四个类库,如下图所示:

 

 将上面8个文件复制到程序输出目录debug下。

网上有文章说将/bin/gdal204.dll文件拷贝到debug目录下,我试了试不管用,程序启动后,抛异常,找不到类库。于是将目录下所有dll都拷贝到debug下,就没有报错了。

三、代码

转换的代码如下所示:

        public static bool TranslateShapeFile(string shapefilepath,string geojsonfilepath)
        {
            bool isok = false;
            try
            {
                LogManager.Write("shapefile文件路径:" + shapefilepath);
                LogManager.Write("geojson文件输出路径:" + geojsonfilepath);
                GdalConfiguration.ConfigureGdal();
                GdalConfiguration.ConfigureOgr();

                if (string.IsNullOrWhiteSpace(shapefilepath) || string.IsNullOrWhiteSpace(geojsonfilepath))
                {
                    LogManager.Write("输入参数路径不合法");
                    return false;
                }

                OSGeo.GDAL.Gdal.AllRegister();
                OSGeo.OGR.Ogr.RegisterAll();

                // 为了支持中文路径,请添加下面这句代码
                OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
                // 为了使属性表字段支持中文,请添加下面这句
                OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "");

                //打开数据
                DataSource ds = Ogr.Open(shapefilepath, 0);
                if (ds == null)
                {
                    LogManager.Write("打开文件失败!");
                    return false;
                }
                Driver dv = Ogr.GetDriverByName("GeoJSON");
                if (dv == null)
                {
                    LogManager.Write("打开驱动失败!");
                    return false;
                }
                dv.CopyDataSource(ds, geojsonfilepath, null);

                isok = true;
            }
            catch(Exception ex)
            {
                LogManager.Write("shapefile文件读取转换失败!");
                LogManager.Write(ex);
            }

            return isok;
        }
代码中有如下两句,是初始化代码,网上的教程上大多都有了。我这是VS里面NuGet添加的gdal引用,自动添加了这个类,后来发现缺失其他类库,就直接下载了类库。自动生成两个文件,一个C#,一个VB版。可新建类,复制过去即可。
GdalConfiguration.ConfigureGdal(); GdalConfiguration.ConfigureOgr();
C#
/******************************************************************************
 *
 * Name:     GdalConfiguration.cs.pp
 * Project:  GDAL CSharp Interface
 * Purpose:  A static configuration utility class to enable GDAL/OGR.
 * Author:   Felix Obermaier
 *
 ******************************************************************************
 * Copyright (c) 2012-2018, Felix Obermaier
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *****************************************************************************/

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Gdal = OSGeo.GDAL.Gdal;
using Ogr = OSGeo.OGR.Ogr;

namespace Utility.ShapeFileToGeoJson
{
    public static partial class GdalConfiguration
    {
        private static volatile bool _configuredOgr;
        private static volatile bool _configuredGdal;
        private static volatile bool _usable;

        [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool SetDefaultDllDirectories(uint directoryFlags);
        //               LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32
        private const uint DllSearchFlags = 0x00000400 | 0x00000800;

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AddDllDirectory(string lpPathName);

        /// <summary>
        /// Construction of Gdal/Ogr
        /// </summary>
        static GdalConfiguration()
        {
            string executingDirectory = null, gdalPath = null, nativePath = null;
            try
            {
                if (!IsWindows)
                {
                    const string notSet = "_Not_set_";
                    string tmp = Gdal.GetConfigOption("GDAL_DATA", notSet);
                    _usable = tmp != notSet;
                    return;
                }

                string executingAssemblyFile = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath;
                executingDirectory = Path.GetDirectoryName(executingAssemblyFile);

                if (string.IsNullOrEmpty(executingDirectory))
                    throw new InvalidOperationException("cannot get executing directory");


                // modify search place and order
                SetDefaultDllDirectories(DllSearchFlags);

                gdalPath = Path.Combine(executingDirectory, "gdal");
                nativePath = Path.Combine(gdalPath, GetPlatform());
                if (!Directory.Exists(nativePath))
                    throw new DirectoryNotFoundException("GDAL native directory not found at '{nativePath}'");
                if (!File.Exists(Path.Combine(nativePath, "gdal_wrap.dll")))
                    throw new FileNotFoundException(
                        "GDAL native wrapper file not found at");

                // Add directories
                AddDllDirectory(nativePath);
                AddDllDirectory(Path.Combine(nativePath, "plugins"));

                // Set the additional GDAL environment variables.
                string gdalData = Path.Combine(gdalPath, "data");
                Environment.SetEnvironmentVariable("GDAL_DATA", gdalData);
                Gdal.SetConfigOption("GDAL_DATA", gdalData);

                string driverPath = Path.Combine(nativePath, "plugins");
                Environment.SetEnvironmentVariable("GDAL_DRIVER_PATH", driverPath);
                Gdal.SetConfigOption("GDAL_DRIVER_PATH", driverPath);

                Environment.SetEnvironmentVariable("GEOTIFF_CSV", gdalData);
                Gdal.SetConfigOption("GEOTIFF_CSV", gdalData);

                string projSharePath = Path.Combine(gdalPath, "share");
                Environment.SetEnvironmentVariable("PROJ_LIB", projSharePath);
                Gdal.SetConfigOption("PROJ_LIB", projSharePath);

                _usable = true;
            }
            catch (Exception e)
            {
                _usable = false;
                //Trace.WriteLine(e, "error");
                //Trace.WriteLine($"Executing directory: {executingDirectory}", "error");
                //Trace.WriteLine($"gdal directory: {gdalPath}", "error");
                //Trace.WriteLine($"native directory: {nativePath}", "error");

                //throw;
            }
        }

        /// <summary>
        /// Gets a value indicating if the GDAL package is set up properly.
        /// </summary>
        public static bool Usable
        {
            get { return _usable; }
        }

        /// <summary>
        /// Method to ensure the static constructor is being called.
        /// </summary>
        /// <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks>
        public static void ConfigureOgr()
        {
            if (!_usable) return;
            if (_configuredOgr) return;

            // Register drivers
            Ogr.RegisterAll();
            _configuredOgr = true;

            PrintDriversOgr();
        }

        /// <summary>
        /// Method to ensure the static constructor is being called.
        /// </summary>
        /// <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks>
        public static void ConfigureGdal()
        {
            if (!_usable) return;
            if (_configuredGdal) return;

            // Register drivers
            Gdal.AllRegister();
            _configuredGdal = true;

            PrintDriversGdal();
        }


        /// <summary>
        /// Function to determine which platform we're on
        /// </summary>
        private static string GetPlatform()
        {
            return Environment.Is64BitProcess ? "x64" : "x86";
        }

        /// <summary>
        /// Gets a value indicating if we are on a windows platform
        /// </summary>
        private static bool IsWindows
        {
            get
            {
                var res = !(Environment.OSVersion.Platform == PlatformID.Unix ||
                            Environment.OSVersion.Platform == PlatformID.MacOSX);

                return res;
            }
        }
        private static void PrintDriversOgr()
        {
#if DEBUG
            if (_usable)
            {
                var num = Ogr.GetDriverCount();
                for (var i = 0; i < num; i++)
                {
                    var driver = Ogr.GetDriver(i);
                    Trace.WriteLine("OGR {i}: {driver.GetName()}", "Debug");
                }
            }
#endif
        }

        private static void PrintDriversGdal()
        {
#if DEBUG
            if (_usable)
            {
                var num = Gdal.GetDriverCount();
                for (var i = 0; i < num; i++)
                {
                    var driver = Gdal.GetDriver(i);
                    Trace.WriteLine("GDAL {i}: {driver.ShortName}-{driver.LongName}");
                }
            }
#endif
        }
    }
}
View Code

VB

'******************************************************************************
'*
'* Name:     GdalConfiguration.vb.pp
'* Project:  GDAL VB.NET Interface
'* Purpose:  A static configuration utility class to enable GDAL/OGR.
'* Author:   Felix Obermaier
'*
'******************************************************************************
'* Copyright (c) 2012-2018, Felix Obermaier
'*
'* Permission is hereby granted, free of charge, to any person obtaining a
'* copy of this software and associated documentation files (the "Software"),
'* to deal in the Software without restriction, including without limitation
'* the rights to use, copy, modify, merge, publish, distribute, sublicense,
'* and/or sell copies of the Software, and to permit persons to whom the
'* Software is furnished to do so, subject to the following conditions:
'*
'* The above copyright notice and this permission notice shall be included
'* in all copies or substantial portions of the Software.
'*
'* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
'* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
'* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
'* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
'* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
'* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
'* DEALINGS IN THE SOFTWARE.
'*****************************************************************************/

Option Infer On

Imports System
Imports System.Diagnostics
Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports Gdal = OSGeo.GDAL.Gdal
Imports Ogr = OSGeo.OGR.Ogr

Namespace Utility.ShapeFileToGeoJson
    ''' <summary>
    ''' Configuration class for GDAL/OGR
    ''' </summary>
    Partial Public Class GdalConfiguration
        Private Shared _configuredOgr As Boolean
        Private Shared _configuredGdal As Boolean
        Private Shared _usable As Boolean

        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
        Public Shared Function SetDefaultDllDirectories(ByVal directoryFlags As UInteger) As Boolean

        End Function

        '    LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32
        Private Const DllSearchFlags As UInteger = &H400 Or &H800

        <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Public Shared Function AddDllDirectory(ByVal lpPathName As String) As <MarshalAs(UnmanagedType.Bool)> Boolean

        End Function

        ''' <summary>
        ''' Construction of Gdal/Ogr
        ''' </summary>
        Shared Sub New()
            Dim nativePath As String = Nothing
            Dim executingDirectory As String = Nothing
            Dim gdalPath As String = Nothing
            Try
                If Not IsWindows Then
                    Const notSet As String = "_Not_set_"
                    Dim tmp As String = Gdal.GetConfigOption("GDAL_DATA", notSet)
                    _usable = (tmp <> notSet)
                    Return
                End If

                Dim executingAssemblyFile As String = New Uri(Assembly.GetExecutingAssembly.GetName.CodeBase).LocalPath
                executingDirectory = Path.GetDirectoryName(executingAssemblyFile)
                If String.IsNullOrEmpty(executingDirectory) Then
                    Throw New InvalidOperationException("cannot get executing directory")
                End If

                SetDefaultDllDirectories(DllSearchFlags)
                gdalPath = Path.Combine(executingDirectory, "gdal")
                nativePath = Path.Combine(gdalPath, GetPlatform())
                If Not Directory.Exists(nativePath) Then
                    Throw New DirectoryNotFoundException($"GDAL native directory not found at '{nativePath}'")
                End If

                If Not File.Exists(Path.Combine(nativePath, "gdal_wrap.dll")) Then
                    Throw New FileNotFoundException($"GDAL native wrapper file not found at '{Path.Combine(nativePath, ", gdal_wrap.dll, ")}'")
                End If

                AddDllDirectory(nativePath)
                AddDllDirectory(Path.Combine(nativePath, "plugins"))
                ' Set the additional GDAL environment variables.
                Dim gdalData As String = Path.Combine(gdalPath, "data")
                Environment.SetEnvironmentVariable("GDAL_DATA", gdalData)
                Gdal.SetConfigOption("GDAL_DATA", gdalData)
                Dim driverPath As String = Path.Combine(nativePath, "plugins")
                Environment.SetEnvironmentVariable("GDAL_DRIVER_PATH", driverPath)
                Gdal.SetConfigOption("GDAL_DRIVER_PATH", driverPath)
                Environment.SetEnvironmentVariable("GEOTIFF_CSV", gdalData)
                Gdal.SetConfigOption("GEOTIFF_CSV", gdalData)
                Dim projSharePath As String = Path.Combine(gdalPath, "share")
                Environment.SetEnvironmentVariable("PROJ_LIB", projSharePath)
                Gdal.SetConfigOption("PROJ_LIB", projSharePath)
                _usable = True
            Catch e As Exception
                _usable = False
                Trace.WriteLine(e, "error")
                Trace.WriteLine($"Executing directory: {executingDirectory}", "error")
                Trace.WriteLine($"gdal directory: {gdalPath}", "error")
                Trace.WriteLine($"native directory: {nativePath}", "error")
                'throw;
            End Try

        End Sub

        ''' <summary>
        ''' Gets a value indicating if the GDAL package is set up properly.
        ''' </summary>
        Public Shared ReadOnly Property Usable As Boolean
            Get
                Return _usable
            End Get
        End Property

        ''' <summary>
        ''' Method to ensure the static constructor is being called.
        ''' </summary>
        ''' <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks>
        Public Shared Sub ConfigureOgr()
            If Not _usable Then
                Return
            End If

            If _configuredOgr Then
                Return
            End If

            ' Register drivers
            Ogr.RegisterAll()
            _configuredOgr = True
            PrintDriversOgr()
        End Sub

        ''' <summary>
        ''' Method to ensure the static constructor is being called.
        ''' </summary>
        ''' <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks>
        Public Shared Sub ConfigureGdal()
            If Not _usable Then
                Return
            End If

            If _configuredGdal Then
                Return
            End If

            ' Register drivers
            Gdal.AllRegister()
            _configuredGdal = True
            PrintDriversGdal()
        End Sub

        ''' <summary>
        ''' Function to determine which platform we're on
        ''' </summary>
        Private Shared Function GetPlatform() As String
            If (Environment.Is64BitProcess) Then Return "x64"
            Return "x86"
        End Function

        ''' <summary>
        ''' Gets a value indicating if we are on a windows platform
        ''' </summary>
        Private Shared ReadOnly Property IsWindows As Boolean
            Get
                Dim res = Not ((Environment.OSVersion.Platform = PlatformID.Unix) _
                            OrElse (Environment.OSVersion.Platform = PlatformID.MacOSX))
                Return res
            End Get
        End Property

        Private Shared Sub PrintDriversOgr()
#If (DEBUG) Then
            If _usable Then
                Dim num = Ogr.GetDriverCount
                Dim i = 0
                Do While (i < num)
                    Dim driver = Ogr.GetDriver(i)
                    Trace.WriteLine($"OGR {i}: {driver.GetName()}", "Debug")
                    i = (i + 1)
                Loop

            End If

#End If
        End Sub

        Private Shared Sub PrintDriversGdal()
#If (DEBUG) Then
            If _usable Then
                Dim num = Gdal.GetDriverCount
                Dim i = 0
                Do While (i < num)
                    Dim driver = Gdal.GetDriver(i)
                    Trace.WriteLine($"GDAL {i}: {driver.ShortName}-{driver.LongName}")
                    i = (i + 1)
                Loop

            End If

#End If
        End Sub
    End Class
End Namespace
View Code

记录一下!

 
posted @ 2019-12-28 16:34  白石江边  阅读(2017)  评论(0编辑  收藏  举报