我花了一些時間嘗試我的Ubuntu的機器上。它花了很多試驗和錯誤,但最終我得到了它的工作。我不確定它是否可以在MacOS或其他* nixes上運行。
許多人懷疑,直接投到char*
沒有工作 - 然後我只得到我的測試路徑/home/progmars/абвгдāēī
的第一個斜線。訣竅是使用wcstombs()
與setlocale()
相結合儘管在轉換後我無法在控制檯上顯示文本,但仍然使用access()
函數。
這裏是爲我工作的代碼:
bool fileExists(const wstring& src)
{
#ifdef PLATFORM_WINDOWS
return (_waccess(src.c_str(), 0) == 0);
#else
// hopefully this will work on most *nixes...
size_t outSize = src.size() * sizeof(wchar_t) + 1;// max possible bytes plus \0 char
char* conv = new char[outSize];
memset(conv, 0, outSize);
// MacOS claims to have wcstombs_l which has locale argument,
// but I could not find something similar on Ubuntu
// thus I had to use setlocale();
char* oldLocale = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "en_US.UTF-8"); // let's hope, most machines will have "en_US.UTF-8" available
// "Works on my machine", that is, Ubuntu 12.04
size_t wcsSize = wcstombs(conv, src.c_str(), outSize);
// we might get an error code (size_t-1) in wcsSize, ignoring for now
// now be good, restore the locale
setlocale(LC_ALL, oldLocale);
return (access(conv, 0) == 0);
#endif
}
這裏是一些實驗性的代碼,使我的解決方案:
// this is crucial to output correct unicode characters in console and for wcstombs to work!
// empty string also works instead of en_US.UTF-8
// setlocale(LC_ALL, "en_US.UTF-8");
wstring unicoded = wstring(L"/home/progmars/абвгдāēī");
int outSize = unicoded.size() * sizeof(wchar_t) + 1;// max possible bytes plus \0 char
char* conv = new char[outSize];
memset(conv, 0, outSize);
size_t szt = wcstombs(conv, unicoded.c_str(), outSize); // this needs setlocale - only then it returns 31. else it returns some big number - most likely, an error message
wcout << "wcstombs result " << szt << endl;
int resDirect = access("/home/progmars/абвгдāēī", 0); // works fine always
int resCast = access((char*)unicoded.c_str(), 0);
int resConv = access(conv, 0);
wcout << "Raw " << unicoded.c_str() << endl; // output /home/progmars/абвгдāēī but only if setlocale has been called; else output is /home/progmars/????????
wcout << "Casted " << (char*)unicoded.c_str() << endl; // output/
wcout << "Converted " << conv << endl; // output /home/progmars/ - for some reason, Unicode chars are cut away in the console, but still they are there because access() picks them up correctly
wcout << "resDirect " << resDirect << endl; // gives correct result depending on the file existence
wcout << "resCast " << resCast << endl; // wrong result - always 0 because it looks for/and it's the filesystem root which always exists
wcout << "resConv " << resConv << endl;
// gives correct result but only if setlocale() is present
當然,我能避免所有的麻煩ifdef
s來定義我自己的字符串版本,在Windows上是wstring
,在* nix上是string
,因爲* nix似乎對UTF8符號更加自由,不介意在純字符串中使用它們。儘管如此,我仍然希望我的函數聲明能夠在所有平臺上保持一致,並且我想了解Unicode文件名在Linux中的工作原理。
'if(std :: ifstream(name))'? – Cynede
對於Linux的情況下,請參閱:http://stackoverflow.com/questions/15470639/how-to-check-if-a-file-exists-in-c – TimDave
@ Heather - 不會自動嘗試打開文件?如果我沒有對現有文件的寫入或讀取權限 - 我不希望'fileExists'在這種情況下返回false。 – JustAMartin