C++ 在Windows上,对于包含奇怪字符的路径,stat和GetFileAttributes失败
下面的代码演示了当路径包含一些奇怪(但有效)的ASCII字符时,stat和GetFileAttributes如何失败。 作为解决方法,我将使用8.3 DOS文件名。但当驱动器禁用了8.3个名称时,这不起作用。 (8.3使用fsutil命令禁用名称:fsutil行为集disable8dot3 1) 在这种情况下,可以让stat和/或GetFileAttributes工作吗? 如果不是,是否有其他方法确定路径是目录还是文件C++ 在Windows上,对于包含奇怪字符的路径,stat和GetFileAttributes失败,c++,windows,C++,Windows,下面的代码演示了当路径包含一些奇怪(但有效)的ASCII字符时,stat和GetFileAttributes如何失败。 作为解决方法,我将使用8.3 DOS文件名。但当驱动器禁用了8.3个名称时,这不起作用。 (8.3使用fsutil命令禁用名称:fsutil行为集disable8dot3 1) 在这种情况下,可以让stat和/或GetFileAttributes工作吗? 如果不是,是否有其他方法确定路径是目录还是文件 #include "stdafx.h" #include <sys/
#include "stdafx.h"
#include <sys/stat.h>
#include <string>
#include <Windows.h>
#include <atlpath.h>
std::wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
// The final characters in the path below are 0xc3 (Ã) and 0x3f (?).
// Create a test directory with the name à and set TEST_DIR below to your test directory.
const char* TEST_DIR = "D:\\tmp\\VisualStudio\\TestProject\\ConsoleApplication1\\test_data\\Ã";
int main()
{
std::string testDir = TEST_DIR;
// test stat and _wstat
struct stat st;
const auto statSucceeded = stat(testDir.c_str(), &st) == 0;
if (!statSucceeded)
{
printf("stat failed\n");
}
std::wstring testDirW = s2ws(testDir);
struct _stat64i32 stW;
const auto statSucceededW = _wstat(testDirW.data(), &stW) == 0;
if (!statSucceededW)
{
printf("_wstat failed\n");
}
// test PathIsDirectory
const auto isDir = PathIsDirectory(testDirW.c_str()) != 0;
if (!isDir)
{
printf("PathIsDirectory failed\n");
}
// test GetFileAttributes
const auto fileAttributes = ::GetFileAttributes(testDirW.c_str());
const auto getFileAttributesWSucceeded = fileAttributes != INVALID_FILE_ATTRIBUTES;
if (!getFileAttributesWSucceeded)
{
printf("GetFileAttributes failed\n");
}
return 0;
}
#包括“stdafx.h”
#包括
#包括
#包括
#包括
std::wstring s2ws(const std::string&s)
{
内伦;
int slength=(int)s.length()+1;
len=MultiByteToWideChar(CP_ACP,0,s.c_str(),slength,0,0);
wchar_t*buf=新的wchar_t[len];
MultiByteToWideChar(CP_ACP,0,s.c_str(),slength,buf,len);
标准:WSTR环(buf);
删除[]buf;
返回r;
}
//下面路径中的最后字符是0xc3(Ã)和0x3f(?)。
//创建一个名为Ã的测试目录,并将下面的test_DIR设置为您的测试目录。
const char*TEST_DIR=“D:\\tmp\\VisualStudio\\TestProject\\ConsoleApplication1\\TEST_data\\Ô;
int main()
{
std::string testDir=TEST_DIR;
//测试状态和_wstat
结构统计;
const auto statsucceeed=stat(testDir.c_str(),&st)==0;
如果(!statsucceed)
{
printf(“stat失败\n”);
}
std::wstring testDirW=s2ws(testDir);
结构stat64i32 stW;
const auto statSucceededW=_wstat(testDirW.data(),&stW)==0;
如果(!statSucceededW)
{
printf(“\u wstat失败\n”);
}
//测试路径目录
const auto isDir=pathidirectory(testDirW.c_str())!=0;
if(!isDir)
{
printf(“路径目录失败\n”);
}
//测试GetFileAttributes
const auto fileAttributes=::GetFileAttributes(testDirW.c_str());
const auto getFileAttributesWSucceeded=文件属性!=无效的文件属性;
如果(!getFileAttributesWSucceeded)
{
printf(“GetFileAttributes失败\n”);
}
返回0;
}
您遇到的问题来自于使用MultiByteToWideChar函数。使用CP_ACP可以默认为不支持某些字符的代码页。如果将默认系统代码页更改为UTF8,代码将正常工作。由于您无法告诉客户要使用什么代码页,因此可以使用第三方库(如Unicode国际组件)将主机代码页转换为UTF16
我使用控制台代码页65001和VS2015运行了您的代码,您的代码按编写的方式运行。我还添加了正数printfs,以验证它是否有效。不要以窄字符串文字开始并尝试转换它,而要以宽字符串文字开始—一个表示实际文件名的文字。您可以使用十六进制转义序列来避免对源代码编码的任何依赖 如果实际代码不使用字符串文字,则最佳分辨率取决于具体情况;例如,如果正在从文件读取文件名,则需要确保知道文件的编码方式,并相应地执行转换 如果实际代码从命令行参数读取文件名,则可以使用wmain()而不是main()将参数作为宽字符串获取。“奇怪(但有效)的ASCII字符”--ASCII仅定义0x00到0x7f范围内的字符。0xc3不在ASCII的范围内。Win特定的解决方法:使用
wchar\u t
而不是char
(或者更好:),还显式使用(和)(无s2ws
,wstring
,…)。