> ## Content Index
> Fetch the complete content index at: https://blog.anthea.day/llms.txt
> Use this file to discover other available public pages before exploring further.

# 歡迎來到 GIS 的世界－Day 11：用 GDAL 處理中文
- URL: https://blog.anthea.day/series-2022-ithome-11/
- Published: 2022-09-24T16:02:23.000Z
- Updated: 2026-10-21T04:10:15.000Z
- Author: Anthea / 芫荽
- Tags: #Migrated-1792241843742, #Import 2026-10-17 12:57, Coding, 2022 iThome 鐵人賽：歡迎來到 GIS 的世界

上一篇提到，輸出的結果中，欄位的名稱可以正常顯示，內容的值卻會變成亂碼。

![](https://cdn-images-1.medium.com/max/800/0*PH0loJ5QjZ0PemvU.png)

上網找解法的時候發現有人遇到[相似的狀況](https://www.cnblogs.com/litou/p/15035790.html?ref=blog.anthea.day)，但不同的是，我和對方的亂碼顯示是相反的：他的亂碼會出現在欄位名稱，內容的值反而是正常的。

雖然狀況有點不相同，但他提出了一套說法：

> 對比 `GetName` 和 `GetFieldAsString` 兩個函數可以很明顯看出來，`GetFieldAsString` 通過調用 `Ogr.Utf8BytesToString` 將返回的 UTF8 編碼的位元組數組以 UTF8 方式解碼為字元串，所以能夠正常顯示；而 GetName 則直接返回字元串（實際上編譯器隱性調用了 `Encoding.Default.GetString` 解碼為字元串），由於沒有使用 UTF8 解碼導致顯示為亂碼。

#### 真的是這樣嗎?

為了證明，我利用反編譯的工具來檢視 `Gdal.Core.dll`，可以看到像下面這樣的內容：

![](https://cdn-images-1.medium.com/max/800/0*9hHW8mu2wghLgd1a.png)

![](https://cdn-images-1.medium.com/max/800/0*5vDq7RxY6cxGpbww.png)

從這兩張圖中可以看到，讀取內容值，調用 `Feature.GetFieldAsString()` 的時候，會將結果進行轉換，`Utf8BytesToString()` 的內容包含：

![](https://cdn-images-1.medium.com/max/800/0*_WRtGQLos2PzG0RA.png)

所以從結論來看，他的情況應該是正常的，只是不知道為甚麼我會是相反的狀況：有用 UTF8 解碼的內容，反而會是亂碼 ?

### 新的希望

按照他的假設和他實際遇到的情況，應該是要在取得欄位名稱的時候多調用 `Utf8BytesToString()` 來讓字串正確顯示。但對於我的狀況來說，反而是要把 `Utf8BytesToString()` 拿掉 ?

這件事對於沒有點 dll 和 C++ 技能的我來說有點困難，所以選擇放棄 `Gdal.Core` 這個套件，轉而使用另外一個使用 Gdal ，但是是專門開發給 .NET Core 使用的套件－－`MaxRev.Gdal.Core`。

![](https://cdn-images-1.medium.com/max/800/1*nSWx_52CGFIG_Yrpe8fiDw.png)

#### 改寫讀取

套件的使用方法和原本的 `Gdal.Core` 一模一樣，只是要在原本的 `Gdal.AllRegister();` 之前，加上 `GdalBase.ConfigureAll();` 就可以了。

記得要先把舊有的 `Gdal.Core` 移除掉喔。

```C#
// 加上這一行
GdalBase.ConfigureAll();
// 原本的註冊
Gdal.AllRegister();
Ogr.RegisterAll();
```

![](https://cdn-images-1.medium.com/max/800/0*2oMboqPenoJ01oz-.png)

成功還原情況了！

### 修正中文亂碼

將情境還原之後就可以針對他所提出的方法進行修正了。我選擇的是第三個方法：直接調用原本 dll 中的方法，再另外包一層 UTF8 解碼。

完整的程式碼如下：

```C#
// 註冊 MaxRev.Gdal.Core
GdalBase.ConfigureAll();

// 註冊 GDAL
Gdal.SetConfigOption("SHAPE_ENCODING", "big5");
Gdal.AllRegister();
Ogr.RegisterAll();

// 開啟 SHP 檔案（0 - 讀取、1 - 讀寫）
var source = Ogr.Open("files/simple/test.shp", (int)EnumShapefileOpen.ReadOnly);
var layerCount = source.GetLayerCount();
for (var i = 0; i < layerCount; i++)
{
    // 讀取圖層 Layer 資訊
    var layer = source.GetLayerByIndex(i);
    var fieldCount = layer.GetLayerDefn().GetFieldCount();
    for (var j = 0; j < fieldCount; j++)
    {
        var field = layer.GetLayerDefn().GetFieldDefn(j);
        
        // 這裡調用新的方法
        var fieldName = GetFieldDfnName(field);
        Console.WriteLine($"欄位{j + 1}. {fieldName}");
    }
    
    // 讀取要素 Feature
    Feature feature;
    while ((feature = layer.GetNextFeature()) != null)
    {
        var id = feature.GetFieldAsInteger(0);
        Console.WriteLine($"內容1. {id}");
        
        var name = feature.GetFieldAsString(1);
        Console.WriteLine($"內容2. {name}");
        
        var area = feature.GetFieldAsInteger64(2);
        Console.WriteLine($"內容3. {area}");
        
        var geometry = feature.GetGeometryRef();
        geometry.ExportToWkt(out var wkt);
        Console.WriteLine($"- WKT: {wkt}");
    }
}

static string? Utf8BytesToString(IntPtr ptr)
{
    if (ptr == IntPtr.Zero)
        return null;
    var ms = new MemoryStream();
    byte b;
    var ofs = 0;
    while ((b = Marshal.ReadByte(ptr, ofs++)) != 0)
    {
        ms.WriteByte(b);
    }
    return Encoding.UTF8.GetString(ms.ToArray());
}

// Dll 的位置要注意
[DllImport("gdal/x64/gdal305.dll", EntryPoint = "OGR_Fld_GetNameRef", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr OGR_Fld_GetNameRef(HandleRef handle);
static string GetFieldDfnName(FieldDefn fieldDefn)
{
    HandleRef handle = FieldDefn.getCPtr(fieldDefn);
    IntPtr ptr = OGR_Fld_GetNameRef(handle);
    return Utf8BytesToString(ptr);
}

public enum EnumShapefileOpen
{
    ReadOnly
}
```

修復成功的結果：

![](https://cdn-images-1.medium.com/max/800/0*BiC2bl-cMo0dMQCy.png)

#### References

- [C#中使用GDAL3（二）：Windows下读写Shape文件及超详细解决中文乱码问题](https://www.cnblogs.com/litou/p/15035790.html?ref=blog.anthea.day)