我有一个阿拉伯文件(ASCII),其中包含: 121101الزبونكمال 121102الزبونسعيد 121103الزبونعمار
我想在C ++中使用std :: ifstream读取此文件:
std::ifstream ifs(file.GetFileName());
std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
当我使用VS IDE观看内容变量时,出现了字符编码错误: 121101ÇÃÒÈæäßãÇá 121102ÇáÒÈæäÓÚíÏ 121103ÇáÒÈæäÚãÇÑ
我还有托盘和std :: wifstream:
std::wifstream ifs2(file.GetFileName());
std::string content2((std::istreambuf_iterator<wchar_t>(ifs2)), std::istreambuf_iterator<wchar_t>());
我有同样的错误。 有人能帮助我吗? 感谢。
答案 0 :(得分:2)
我有一个阿拉伯语文件(ASCII),其中包含:121101الزبونكمال 121102الزبونسعيد121103الزبونعمار
经过一番澄清后,OP希望:
编写读取uft8和ANSI文件的通用函数
为了能够以相同的方式处理内容,我建议转换为UTF-16编码的std::wstring
。 OP似乎是针对Windows平台开发的,其中UTF-16是大多数API所期望的编码。在其他平台(Linux)上,将所有内容转换为UTF-8可能更合适。
为了能够解码ANSI(又名扩展ASCII),我们必须知道文件的codepage。
可以通过流的imbue()
方法定义代码页(或更准确地说是语言环境)。在您的情况下,代码页为1256。
以下示例读取使用ANSI代码页1256编码的文本文件的内容,并使用需要UTF-16编码字符串的MessageBoxW()
显示文本:
#include <fstream>
#include <string>
#include <codecvt>
#include <Windows.h>
int main()
{
// Use wifstream because we want to read content into a wstring.
std::wifstream f{"test.txt"};
// Define the code page of the text file (1256 = Arabic)
f.imbue( std::locale( ".1256" ) );
// Read the whole file into a wstring.
// The stream converts from ANSI to UTF-16 encoding.
std::wstring s{ std::istreambuf_iterator<wchar_t>( f ), std::istreambuf_iterator<wchar_t>() };
// Display the string which is now UTF-16 encoded.
::MessageBoxW( NULL, s.c_str(), L"test", 0 );
return 0;
}
注意:std::locale
参数是特定于平台的。 “.1256”适用于Windows平台,但这可能不适用于Linux。
为此,我们可以使用std::codecvt_utf8_utf16
方面。
使用以下代码替换上一个示例的imbue()
调用:
f.imbue( std::locale( f.getloc(),
new std::codecvt_utf8_utf16< wchar_t, 1114111UL, std::consume_header> ) );
标记std::consume_header
会跳过byte order mark(如果存在)。
备注:强>
上面提供的代码示例要求您事先知道文本文件的编码。以真正通用的方式检测文本文件的编码是一项艰巨的任务,因为没有标准的方法可以做到这一点。它不能可靠地完成,你必须使用一些启发式方法。
如果你可以对你必须处理的文件做一些假设,你可以写一个简单的检测功能。假设文件只属于以下类别:
然后,您可以使用std::ifstream
读取文件的前3个字节,并将其与{0xEF, 0xBB, 0xBF}
进行比较。如果相等,则可以相对确定该文件是UTF-8编码的,因为非UTF-8编码的文件不太可能以这些字节开头。如果不相等,您将假设代码页1256。
答案 1 :(得分:-3)
为什么不使用FILE *?例如,这是我的代码的摘录,我正在为我的游戏阅读save.ini,其中包含不同的保存游戏条目。我喜欢fopen()的是你实际上可以知道文件的格式(如UTF-8,UTF-16等)。
FILE* pFini = fopen ("save\\save.ini", "rt,ccs=UTF-8");
int iLine = 0;
if (pFini == NULL)
{
cout << "WARNING: cannot open save.ini file." << endl;
return;
}
while (!feof (pFini))
{
fgetws (wSaveGames [iLine], 125, pFini);
iLine++;
if (iLine >= MAX_SAVEGAME_NUMBER)
break;
}
fclose (pFini);