C++ 如何在创建文件之前检查文件是否已存在?(C+;+;,Unicode,跨平台)
我有以下适用于Windows的代码:C++ 如何在创建文件之前检查文件是否已存在?(C+;+;,Unicode,跨平台),c++,unicode,filesystems,cross-platform,file-exists,C++,Unicode,Filesystems,Cross Platform,File Exists,我有以下适用于Windows的代码: bool fileExists(const wstring& src) { #ifdef PLATFORM_WINDOWS return (_waccess(src.c_str(), 0) == 0); #else // ???? how to make C access() function to accept the wstring on Unix/Linux/MacOS ? #endif } 考虑到scr
bool fileExists(const wstring& src)
{
#ifdef PLATFORM_WINDOWS
return (_waccess(src.c_str(), 0) == 0);
#else
// ???? how to make C access() function to accept the wstring on Unix/Linux/MacOS ?
#endif
}
考虑到scr
是一个Unicode字符串,可能包含带有Unicode字符的文件路径,我如何使代码在*nix平台上与在Windows上的工作方式相同
我看到了各种各样的答案,它们部分地回答了我的问题,但我很难把它们放在一起。我的系统依赖于宽字符串,尤其是在文件名可能包含非ASCII字符的Windows上。我知道一般情况下最好写入文件并检查错误,但我的情况正好相反——如果文件已经存在,我需要跳过它。我只想检查文件是否存在,不管我是否能读/写它。在FAT和NTFS以外的许多文件系统上,文件名并没有准确地定义为字符串。从技术上讲,它们是字节序列。这些字节序列的含义是一个解释问题。一种常见的解释是类似UTF-8的。不完全是UTF-8,因为不管编码如何,Unicode都指定字符串相等。大多数系统使用字节相等。(同样,FAT和NTFS是例外,使用不区分大小写的比较)我使用的一个好的便携式解决方案是使用以下内容:
ifstream my_file(myFilenameHere);
if (my_file.good())
{
// file exists and do what you need to do when it exists
}
else
{
// the file doesn't exist do what you need to do to create it etc.
}
例如,一个小文件存在性检查功能可以是(此功能适用于windows、linux和unix):
上面的函数使用最快的方法检查每个操作系统变体的文件,并且在您使用的操作系统不是明确列出的操作系统(例如,原始的Amiga操作系统)时具有回退功能。这已在GCC4.8.x和VS 2010/2012中使用
该方法将检查所有内容是否正常,这样您就可以实际打开文件
唯一需要注意的是,请密切注意文件名在操作系统中的表示方式(如另一个答案中所述)
到目前为止,这对我来说在跨平台上运行得很好:)我花了几个小时在我的Ubuntu机器上进行实验。它经历了多次尝试和错误,但最终我还是成功了。我不确定它是否能在MacOS甚至其他*尼克斯上运行 正如许多人怀疑的那样,直接转换到
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
//这对于在控制台中输出正确的unicode字符以及wcstombs的工作至关重要!
//空字符串也可以代替en_US.UTF-8
//setlocale(LC_ALL,“en_US.UTF-8”);
wstring UNICODE=wstring(L)/主/程序/ббббббббббббб;
int outSize=unicoded.size()*sizeof(wchar\u t)+1;//最大可能字节数加上\0个字符
char*conv=新字符[超大];
memset(conv,0,特大型);
size_t szt=wcstombs(conv,unicoded.c_str(),特大号);//这需要setlocale—只有在返回31时才需要。否则它会返回一些大的数字——很可能是一条错误消息
wcoutif(std::ifstream(name))
?对于linux案例,请参阅:@Heather-这不会自动尝试打开文件吗?如果我没有对现有文件的写入或读取权限,该怎么办?在这种情况下,我不希望fileExists
返回false。@TimDave-不幸的是,这不能解释我应该如何处理wstringaccess()
想要char*
但我只能从wstring中获得wchar\u t*
。在*nix平台上将wstring::c_str()
转换为char*
安全吗?@Martin那么您的问题是关于如何将wstring转换为char*?谢谢您的代码。不幸的是,我无法使用它有两个问题:1)我想知道该文件存在,即使我没有打开它的权限-fopen
对我不起作用,2)如果文件名包含Unicode字符,例如,āēīāāāāāāāāāāāā。我生活在一个我们习惯于使用来自不同ANSI代码页的符号的拉脱维亚和俄罗斯文件名的国家,因此只有Windows Unicode API能够正确处理它们。啊,我现在明白了,把它留给我吧,今晚我将在使Unicode更加敏感方面大展拳脚:)这太棒了。它真的帮助了我。谢谢
// 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