c++ builder 中怎么判断txt(记事本)文件是不是utf8编码?(在线等)
c++ builder 中怎么判断txt(记事本)文件是不是utf8编码?
下面是一段UTF8转ASCII的代码,我想加个判断,当文件不是UTF8时就不转换,但用memcmp函数判断不管用,请问要怎么判断啊?
void UTF8FileConvertToAnsi(char *srcFile,char *destFile)
{
char UTF8Header[3] = {0xef,0xbb,0xbf};
char *srcBuff;
char *destBuff;
int hFile;
int nSize;
if (!FileExists(srcFile)) {
return;
}
hFile = FileOpen(srcFile,0);
nSize = FileSeek(hFile,0,2);
if (nSize < 3) {
FileClose(hFile);
return;
}
srcBuff = (char*)malloc(3);
FileSeek(hFile,0,0);
FileRead(hFile, srcBuff, 3);
FileSeek(hFile,0,0);
//if (memcmp(UTF8Header,srcBuff,3)) {
free(srcBuff);
destBuff = (char*)malloc(nSize);
memset(destBuff,0x00,nSize);
srcBuff = (char*)malloc(nSize + 1);
memset(srcBuff,0x00,nSize + 1);
FileRead(hFile, srcBuff, nSize);
FileClose(hFile);
strcpy(destBuff,Utf8ToAnsi(srcBuff).c_str());
hFile = FileCreate(destFile);
FileWrite(hFile,destBuff,strlen(destBuff));
FileClose(hFile);
free(destBuff);
free(srcBuff);
}
[解决办法]
UTF8编码其实和Unicode是同类,就是在编码方式上不同。
首先UTF8编码后的大小是不一定,不像Unicode编码后的大小是一样的。Unicode的编码中一个英文字母 “a” 和 一个汉字 “好”,编码后都是占用的空间大小是一样的,都是两个字节。而UTF8编码中一个英文字母“a” 和 一个汉字 “好”,编码后占用的空间大小就不样了,前者是一个字节,后者是三个字节。
UTF8编码的原理:因为一个字母还有一些键盘上的符号加起来只用二进制七位就可以表示出来,而一个字节就是八位,所以UTF8就用一个字节来表式字母和一些键盘上的符号。然而当我们拿到被编码后的一个字节后怎么知道它的组成?它有可能是英文字母的一个字节,也有可能是汉字的三个字节中的一个字节!所以,UTF8是有标志位的。
当要表示的内容是7位的时候就用一个字节:0******* 第一个0为标志位,剩下的空间正好可以表示ASCII码0-127的内容。当要表示的内容在8到11位的时候就用两个字节:110***** 10******第一个字节的110和第二个字节的10为标志位。
当要表示的内容在12到16位的时候就用三个字节:1110***** 10****** 10******和上面一样,第一个字节的1110和第二、三个字节的10都是标志位,剩下的空间正好可以表示汉字。
依次类推:
四个字节:11110**** 10****** 10****** 10******
五个字节:111110*** 10****** 10****** 10****** 10******
六个字节:1111110** 10****** 10****** 10****** 10****** 10******
[解决办法]
/* IsTextUTF8
*
* UTF-8 is the encoding of Unicode based on Internet Society RFC2279
* ( See http://www.cis.ohio-state.edu/htbin/rfc/rfc2279.html )
*
* Basicly:
* 0000 0000-0000 007F - 0xxxxxxx (ascii converts to 1 octet!)
* 0000 0080-0000 07FF - 110xxxxx 10xxxxxx ( 2 octet format)
* 0000 0800-0000 FFFF - 1110xxxx 10xxxxxx 10xxxxxx (3 octet format)
* (this keeps going for 32 bit unicode)
*
*
* Return value: TRUE, if the text is in UTF-8 format.
* FALSE, if the text is not in UTF-8 format.
* We will also return FALSE is it is only 7-bit ascii, so the right code page
* will be used.
*
* Actually for 7 bit ascii, it doesn 't matter which code page we use, but
* notepad will remember that it is utf-8 and "save " or "save as " will store
* the file with a UTF-8 BOM. Not cool.
*/
INT IsTextUTF8( LPSTR lpstrInputStream, INT iLen )
{
INT i;
DWORD cOctets; // octets to go in this UTF-8 encoded character
UCHAR chr;
BOOL bAllAscii= TRUE;
cOctets= 0;
for( i=0; i < iLen; i++ ) {
chr= *(lpstrInputStream+i);
if( (chr&0x80) != 0 ) bAllAscii= FALSE;
if( cOctets == 0 ) {
//
// 7 bit ascii after 7 bit ascii is just fine. Handle start of encoding case.
//
if( chr > = 0x80 ) {
//
// count of the leading 1 bits is the number of characters encoded
//
do {
chr < <= 1;
cOctets++;
}
while( (chr&0x80) != 0 );
cOctets--; // count includes this character
if( cOctets == 0 ) return FALSE; // must start with 11xxxxxx
}
}
else {
// non-leading bytes must start as 10xxxxxx
if( (chr&0xC0) != 0x80 ) {
return FALSE;
}
cOctets--; // processed another octet in encoding
}
}
//
// End of text. Check for consistency.
//
if( cOctets > 0 ) { // anything left over at the end is an error
return FALSE;
}
if( bAllAscii ) { // Not utf-8 if all ascii. Forces caller to use code pages for conversion
return FALSE;
}
return TRUE;
}
[解决办法]
http://blog.csdn.net/fjye/archive/2007/02/02/1501442.aspx
[解决办法]
UTF8/UTF16等编码的文件,主要分为两种,一种是有标识头的,一种是无标识头的,通常在讨论的时候,只讨论有标识头的。先读取前三个字节,判断编码(UTF8三个,UTF16只须两个)。对于只有几个字节的数据,无须采用memcmp,而直接采用等于操作符就可以。由于考虑到文件可能会比较大,以及编码问题,不建议采用Utf8ToAnsi进行转换。最好的办法是MultiByteToWideChar/WideCharToMultiByte进行映视。否则的话会由于当前系统的编码与原始文件内容的编码不一致而导致乱码(比如说一篇GBK码字元组成的文章,被存为UTF8编码文件之后,再转换的时候,如果当前系统默认是BIG5编码,那么将导致部分GBK/Unicode文字在BIG5字符集当中得不到对应而被默认字符如问号等字元代替)。
[解决办法]
to 楼主,给你一个我自己写的判断文件编码格式的函数吧,另外如果UTF8编码文件很短的话可能会误判,这个就是windows下记事本的那个 "联通 "的bug,不过处理一般的utf8编码已经足够了
BYTE FileType()
{
const char File_Unicode_Character[2]={0xFF,0xFE};
const char File_UTF8_Character[3]={0xEF,0xBB,0xBF};
BYTE bFileType;
char buff[4]={NULL};
FILE *fp;
fp=fopen(PathName.c_str(), "r ");
if(!fp)
{
fclose(fp);
bFileType = Error_File;
return bFileType;
}
fread(buff,1,3,fp);//共读取3个字节
fclose(fp);
if(!memicmp(buff,File_UTF8_Character,sizeof(File_UTF8_Character)))
{
bFileType = File_UTF8;
}
else if(!memicmp(buff,File_Unicode_Character,sizeof(File_Unicode_Character)))
{
bFileType = File_Unicode;
}
else
{
TMemoryStream *ss;
ss=new TMemoryStream();
ss-> LoadFromFile(PathName);
int size=ss-> Size;
unsigned char *p=new char[size+1];
memset(p,0x00,size+1);
ss-> Read(p,size);
if(IsTextUTF8(p,size))
{
bFileType = File_UTF8_NOBOM;
}
else
{
bFileType = File_GBK;
}
delete []p;
delete ss;
}
return bFileType;
}
[解决办法]
直接用Utf8ToAnsi(),如里返回空值就不是UTF-8编码
====================================================
我现在的问题就是,是Utf8的用Utf8ToAnsi()转成Ansi,对于不是UTF-8编码的,不能用Utf8ToAnsi(),否则文件变空文件了,数据全部丢失了,这样在转换前就必须判断它是否是Utf8编码。现在问题就是不知道怎么判断
====================================================
Utf8ToAnsi()不去操作文件,如果不是UTF-8编码的,它返回IsEmpty()为true的AnsiString,文件里的内容又不会变.它的输入参数只是一个AnsiString而已.
另外,我认为关于“联通”的BUG任何方法都不能正确判断,因为GB2312的 "联通 "也是合法的UTF-8编码. 就象上楼说的,很短的文本就是会存在误判的