GDAL讀取S-57海圖資料中文屬性值亂碼問題解決

來源:互聯網
上載者:User

使用GDAL讀取S-57海圖資料時,對於屬性工作表中的中文屬性值讀出來是亂碼。1所示。

圖1 S57海圖資料中文亂碼欄位

通過調試代碼發現,S-57檔案中的中文是按照寬位元組儲存在檔案中,而GDAL在讀取時統一按照單位元組來讀取,這樣就直接導致了中文屬性值的亂碼。比如這裡有個欄位屬性值為“北京市”,讀出來顯示為“S琋^”,對應的十六進位為“0x17 0x53 0xac 0x4e 0x02 0x5e 0x1f 0x00”。

本以為GDAL中會有個設定選項來設定編碼,S57的源碼翻遍了也沒找到設定選項,看來只能自力更生了,那就是自己寫個轉換函式來進行轉換。修改GDAL庫的源碼工作量有點大,還是直接在外面處理吧。首先我們要寫一個把寬位元組轉為單位元組的函數。代碼如下:

string ConvertWchar2Char(const wstring &str){size_t len = wcstombs(NULL, str.c_str(), 0)*2 + 1;char *pszDst = new char[len];setlocale(LC_ALL,"");     //設定本地預設Localeint len1 = wcstombs(pszDst, str.c_str(), len);setlocale(LC_ALL,"C");     //預設if(len1 == -1){delete []pszDst;throw runtime_error("wcstombs(): unable to convert character");}string strChar = string(pszDst, len);delete []pszDst;return strChar;}

有了上面的函數,我們就可以在讀取屬性值後,調用上面的函數進行轉換就OK了。需要注意的是,GDAL中擷取的屬性值傳回值是一個const char*格式,表面看起來是個單位元組,但實質記憶體儲存的確是多位元組,所以我們需要強制類型轉換轉為多位元組,程式碼片段如下:

const char* pszValue = poFeature->GetFieldAsString("NOBJNM");wstring strwValue = (const wchar_t*)pszValue;//轉換為單位元組string strValue = ConvertWchar2Char(strwValue);

第一句返回的是一個const char*,然後直接強制類型轉為const wchar_t*類型,然後構造一個wstring類型。最後使用上面的函數進行轉換即可得到最終的結果值。完整的測試代碼如下:

#include <stdio.h>#include <string>#include "ogrsf_frmts.h"#include "ogr_spatialref.h"using namespace std;string ConvertWchar2Char(const wstring &str){size_t len = wcstombs(NULL, str.c_str(), 0)*2 + 1;char *pszDst = new char[len];setlocale(LC_ALL,"");     //設定本地預設Localeint len1 = wcstombs(pszDst, str.c_str(), len);setlocale(LC_ALL,"C");     //預設if(len1 == -1){delete []pszDst;throw runtime_error("wcstombs(): unable to convert character");}string strChar = string(pszDst, len);delete []pszDst;return strChar;}int ReadS57()  {  CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");  OGRRegisterAll();  //開啟資料  const char* pszS57 = "D:\\C1100102.000";  OGRDataSource *poDS = OGRSFDriverRegistrar::Open(pszS57, FALSE );  if( poDS == NULL )  {  printf( "Open failed.\n" );  return 1;  }  // 擷取有中文屬性值的圖層  OGRLayer *poLayer = poDS->GetLayerByName( "BUAARE" );  if( poLayer == NULL )  {  printf( "Get Layer failed.\n" );  OGRDataSource::DestroyDataSource( poDS );  return 1;  }  poLayer->ResetReading();  OGRFeature *poFeature = poLayer->GetNextFeature();  while (poFeature != NULL )  {  OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();   //擷取屬性欄位值  // 為了示範說明,就只輸出亂碼的屬性值  string strValue = poFeature->GetFieldAsString("NOBJNM"); if (strValue != ""){char* pszValue = (char*)strValue.c_str();size_t ilast = strlen(pszValue);pszValue[ilast-1] = '\0';wstring strwValue = (const wchar_t*)pszValue;  //轉換為單位元組  strValue = ConvertWchar2Char(strwValue);  }printf("%s\n", strValue.c_str());  OGRFeature::DestroyFeature( poFeature );  poFeature = poLayer->GetNextFeature();  }  OGRDataSource::DestroyDataSource( poDS );  return 0;  }int main(){// 先測試轉換函式是否正常工作const char* pszValue = "S琋^";wstring str =  (const wchar_t*)pszValue;string strTemp = ConvertWchar2Char(str);printf("%s\n", strTemp.c_str());wstring str1 = L"Hello1234";strTemp = ConvertWchar2Char(str1);printf("%s\n", strTemp.c_str());// 讀取S57海圖資料ReadS57();return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.