上篇博文中的代碼使用了函數wcstombs來進行處理,今天發現GDAL庫裡面提供了寬位元組轉單位元組的函數,名字叫CPLRecodeFromWChar(這個函數需要libiconv庫的支援,也就是在編譯GDAL的時候需要把libiconv庫一起編譯)。本以為C#語言也可以使用,結果很悲劇的發現,C#的提供的介面中沒有相關的函數,看來使用C#的同學有點悲劇了。
需要說明的是,需要先用函數CPLRecodeFromWChar將寬位元組轉為UTF8,然後再使用函數CPLRecode將UTF8轉為漢字編碼(CP936)。
程式依舊是昨天的那個,函數全部換成GDAL的函數,代碼如下:
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(); //擷取屬性欄位值 // 為了示範說明,就只輸出亂碼的屬性值 const char* pszAttValue = poFeature->GetFieldAsString("NOBJNM"); size_t size = strlen(pszAttValue);if (size != 0){char* pszValue = new char[size];memcpy(pszValue, pszAttValue, size);pszValue[size-1] = '\0';char *pszGetUTF8 = CPLRecodeFromWChar( (const wchar_t*)pszValue, CPL_ENC_UCS2, CPL_ENC_UTF8);pszAttValue = CPLRecode( pszGetUTF8, CPL_ENC_UTF8, "");delete []pszValue;}printf("%s\n", pszAttValue); OGRFeature::DestroyFeature( poFeature ); poFeature = poLayer->GetNextFeature(); } OGRDataSource::DestroyDataSource( poDS ); return 0; }
是執行輸出的結果,和使用QGIS開啟對比。
通過上面的方式是可以解決這個問題,不過稍微有點麻煩,需要在每次擷取屬性值的時候都要進行判斷。我們可以直接修改GDAL庫中的代碼,這樣在讀取的時候直接就是漢字編碼。找了一下午,在GDAL庫的源碼中檔案gdal-1.9.2\ogr\ogrsf_frmts\s57\s57reader.cpp行883左右,修改為下面:
// Add By liml 2013-04-25 Convert UCS-2 to Utf-8const char* pachBuffer = poRecord->GetStringSubfield("NATF",0,"ATVL",iAttr);if( EQUAL(pszAcronym, "NOBJNM")){size_t nLength = strlen(pachBuffer);char* pszValue = new char[nLength];memcpy(pszValue, pachBuffer, nLength);pszValue[nLength-1] = '\0';char *pszGetUTF8 = CPLRecodeFromWChar( (const wchar_t*)pszValue, CPL_ENC_UCS2, CPL_ENC_UTF8);pachBuffer = CPLRecode( pszGetUTF8, CPL_ENC_UTF8, CPL_ENC_LOCALE);delete []pszValue;}// Add By liml 2013-04-25 poFeature->SetField( pszAcronym, pachBuffer);
下面是使用ogrinfo輸出的對比情況,左邊是沒修改時輸出的,右邊是修改後輸出的。
雖然這麼修改是可以解決這個問題,但是不知道會不會引起其他的副作用。等發現了再修改吧。修改之後的GDAL庫已經上傳至我的資源中心,有需要的同學可以自行去下載。