宽字符窄字符的转化
问题
当step文件的存放路径有中文时,会导致读取失败。
宽、窄字符
在C和C++中,宽字符(wide characters)和窄字符(narrow characters)是用来表示字符的不同方式。
宽字符(wide characters):
- 宽字符通常使用多个字节来表示一个字符,通常采用 Unicode 编码方式,比如 UTF-16 或 UTF-32。
- 在C和C++中,宽字符类型通常是
wchar_t
类型,用于表示宽字符。 - 宽字符用于处理各种语言中的特殊字符、符号以及其他语言特定的文本处理需求,因为 Unicode 编码支持了几乎所有的语言字符。
窄字符(narrow characters):
- 窄字符是使用单个字节来表示一个字符,通常采用 ASCII 或其他类似的编码方式。
- 在C和C++中,窄字符类型通常是
char
类型。 - 窄字符通常用于处理英文、数字和一些基本的符号,它们可以直接在单字节字符编码中表示。
因为我们使用string来存放字符串,因此当路径字符串中有中文时,我们需要将其转换为宽字符(wstring)然后再转换为窄字符(string)。
通过将 string
类型的路径转换为 wstring
类型,然后再转换回 string
类型,可以避免在窄字符编码下的限制。即使最终路径是 string
类型,但由于在转换过程中使用了宽字符编码,因此能够正确处理中文字符,从而使 ReadFile
函数能够读取到正确的路径并成功打开文件。
std::wstring StringToWstring::StoWs(std::string str)
{
const char* sBuf = str.c_str();
//获取输入缓存大小
int sBufSize = static_cast<int>(str.size()) + 1; // 包括终止符
//获取输出缓存大小
//VC++ 默认使用ANSI,故取第一个参数为CP_ACP
DWORD dBufSize = MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, NULL, 0);
printf("需要wchar_t%u个\n", dBufSize);
wchar_t* dBuf = new wchar_t[dBufSize];
wmemset(dBuf, 0, dBufSize);
//进行转换
int nRet = MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, dBuf, dBufSize);
if (nRet <= 0)
{
std::cout << "转换失败" << std::endl;
DWORD dwErr = GetLastError();
switch (dwErr)
{
case ERROR_INSUFFICIENT_BUFFER:
printf("ERROR_INSUFFICIENT_BUFFER\n");
break;
case ERROR_INVALID_FLAGS:
printf("ERROR_INVALID_FLAGS\n");
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER\n");
break;
case ERROR_NO_UNICODE_TRANSLATION:
printf("ERROR_NO_UNICODE_TRANSLATION\n");
break;
}
}
else
{
std::cout << "转换成功" << std::endl;
std::cout << dBuf;
}
return dBuf;
}
void stpRead(std::string& stp_location, TopoDS_Shape& shape)
{
StringToWstring ws;
std::wstring wideStr1 = ws.StoWs(stp_location);
//宽字符保存中文路径
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
//将宽字符路径转换为窄字符路径
std::string narrowFilePath = converter.to_bytes(wideStr1);
STEPControl_Reader reader;
IFSelect_ReturnStatus status = reader.ReadFile(narrowFilePath.c_str());
// 检查读取状态
if (status != IFSelect_RetDone) {
std::cout << "无法读取文件" << std::endl;
}
// 转化为 TopoDS_Shape 存储
if (reader.TransferRoots()) { // 转化为OCC结构存入reader中
shape = reader.OneShape();
}
else
{
std::cout << "step读取实体失败!" << std::endl;
}
}
这段代码使用了 std::wstring_convert
和 std::codecvt_utf8
类来进行宽字符(std::wstring
)到窄字符(std::string
)的转换,主要用于将宽字符路径转换为窄字符路径。
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
:- 这一行创建了一个
std::wstring_convert
对象,指定了使用std::codecvt_utf8<wchar_t>
类型的转换器。这个转换器用于将宽字符(wchar_t
)编码的字符串转换为 UTF-8 编码的窄字符(char
)编码的字符串。
- 这一行创建了一个
std::string narrowFilePath = converter.to_bytes(wideStr1);
:- 这一行调用了
to_bytes
方法,将std::wstring
类型的wideStr1
转换为std::string
类型的narrowFilePath
。 to_bytes
方法接受一个std::wstring
类型的参数,并将其转换为窄字符编码,通常是 UTF-8 编码,最终返回一个std::string
类型的结果。
rowFilePath`。to_bytes
方法接受一个std::wstring
类型的参数,并将其转换为窄字符编码,通常是 UTF-8 编码,最终返回一个std::string
类型的结果。- 因为
ReadFile
函数需要接受窄字符路径(即const char*
类型),所以这一步是必要的,以便将宽字符路径转换为窄字符路径,以便后续的文件读取操作。
- 这一行调用了