GDAL1.8.0發布很久了,一直沒有將自己的工程中的版本更新到1.80。今天將其更新到1.80發現含有中文路徑的檔案都不能開啟了,影像和向量檔案都是。仔細對比了GDAL1.72和GDAL1.80的代碼,終於發現了問題的所在之處,詳細代碼在GDAL_HOME\port\cpl_vsil_win32.cpp檔案中的類VSIWin32FilesystemHandler中,以Stat()函數為例(435行),其他函數類似。代碼如下: GDAL1.8.0代碼(部分):
/************************************************************************//* Stat() *//************************************************************************/int VSIWin32FilesystemHandler::Stat( const char * pszFilename, VSIStatBufL * pStatBuf, int nFlags ){ (void) nFlags;#if (defined(WIN32) && _MSC_VER >= 1310) || __MSVCRT_VERSION__ >= 0x0601 if( CSLTestBoolean( CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" ) ) ) { int nResult; wchar_t *pwszFilename = CPLRecodeToWChar( pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2 ); nResult = _wstat64( pwszFilename, pStatBuf ); CPLFree( pwszFilename ); return nResult; } else#endif { return( VSI_STAT64( pszFilename, pStatBuf ) ); }}
GDAL1.7.2代碼(部分):
/************************************************************************//* Stat() *//************************************************************************/int VSIWin32FilesystemHandler::Stat( const char * pszFilename, VSIStatBufL * pStatBuf ){ return( VSI_STAT64( pszFilename, pStatBuf ) );}
通過上面的代碼對比,就會看到,原來在函數中添加了一個CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" )判斷,通過判斷是否是UTF8的編碼,而且指定的預設值還是UTF8編碼,在含有中文路徑的字串大多數的編碼應該是GBK的編碼,這樣,系統就將GBK的編碼當做UTF8的編碼來進行轉換,結果就是漢字全部是亂碼,導致的結果就是找不到檔案,所以打不開。
知道原因,那麼解決的方式就知道了,大概有下面幾種,各有優劣,供大家選擇 1:不改變GDAL原始碼,在自己調用GDALRegisterAll()和OGRAllRegiser()函數後,加上下面一句即可。 CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");這樣的優點是,不用改動GDAL的原始碼,但是如果自己的工程中經常開啟映像的話,每次都要加,比較麻煩。 2:修改GDAL原始碼,將下面一句 CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");分別添加到GDALAllRegister()函數【GDAL_HOME\frmts\gdalallregister.cpp73行左右】和OGRRegisterAll()函數【GDAL_HOME\ogr\ogrsf_frmts\generic\ogrregisterall.cpp38行左右】中,然後重新編譯GDAL即可。這樣的方式就和使用以前版本的GDAL一樣了,不用改動自己的代碼,推薦使用這種方式。3:修改GDAL原始碼,GDAL_HOME\port\cpl_vsil_win32.cpp檔案中的全部去掉CPLGetConfigOption全部去掉,或者將後面的YES改為NO,但是該工作量巨大,而且有好多地方,這種方式不推薦。
希望對那些還在為GDAL180中文路徑亂碼糾結的人們有所協助。尤其是看到好多人在外面先把中文路徑轉成utf8的編碼,然後再調用GDAL的函數。