以下是我的情况:我需要正确确定哪个字符编码用于给定的文本文件。希望它能正确返回以下类型之一:
enum CHARACTER_ENCODING
{
ANSI,
Unicode,
Unicode_big_endian,
UTF8_with_BOM,
UTF8_without_BOM
};
到目前为止,我可以通过调用以下函数正确地告诉文本文件Unicode
,Unicode big endian
或UTF-8 with BOM
。如果给定的文本文件最初不是ANSI
,它也可以正确地确定UTF-8 without BOM
。 问题是,当文本文件为UTF-8 without BOM
时,以下函数会误将其视为ANSI
文件。
CHARACTER_ENCODING get_text_file_encoding(const char *filename)
{
CHARACTER_ENCODING encoding;
unsigned char uniTxt[] = {0xFF, 0xFE};// Unicode file header
unsigned char endianTxt[] = {0xFE, 0xFF};// Unicode big endian file header
unsigned char utf8Txt[] = {0xEF, 0xBB};// UTF_8 file header
DWORD dwBytesRead = 0;
HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
CloseHandle(hFile);
throw runtime_error("cannot open file");
}
BYTE *lpHeader = new BYTE[2];
ReadFile(hFile, lpHeader, 2, &dwBytesRead, NULL);
CloseHandle(hFile);
if (lpHeader[0] == uniTxt[0] && lpHeader[1] == uniTxt[1])// Unicode file
encoding = CHARACTER_ENCODING::Unicode;
else if (lpHeader[0] == endianTxt[0] && lpHeader[1] == endianTxt[1])// Unicode big endian file
encoding = CHARACTER_ENCODING::Unicode_big_endian;
else if (lpHeader[0] == utf8Txt[0] && lpHeader[1] == utf8Txt[1])// UTF-8 file
encoding = CHARACTER_ENCODING::UTF8_with_BOM;
else
encoding = CHARACTER_ENCODING::ANSI; //Ascii
delete []lpHeader;
return encoding;
}
这个问题已经阻止了我很长时间,我仍然找不到一个好的解决方案。任何暗示都将受到赞赏。
答案 0 :(得分:7)
对于初学者来说,没有像" Unicode"这样的物理编码。您可能的意思是UTF-16。其次,任何文件在" ANSI"中都有效,或者就此而言是任何单字节编码。你能做的唯一事情就是以最佳顺序 guess ,最有可能抛出无效的匹配。
您应该按此顺序检查:
如果您希望UTF-16文件没有 BOM(例如,它可以用于指定XML声明中的编码的XML文件),那么您必须推动那个规则也在那里。虽然上述任何一种都可能产生误报,但错误地将ANSI文件识别为UTF- *(尽管它不太可能)。您应始终使用元数据来告诉您文件的编码,在无法实现100%准确率的情况下检测文件。