【无标题】

https://www.cnblogs.com/2015-16/p/16588327.html

MFC实现Txt04之打开各种编码文本(ANSI,UTF-8,UTF-16)

// 新版本,支持多种Txt文本的读取(UTF-8BOM、ANSI、Unicode16-LE、UTF-8)
//            // 以什么格式打开,就以什么格式写回去(没实现这个功能)
bool CTxt0721View::ReadFileContents()
{
    CFile read_file;
    DWORD file_length;            // 文件字节长度
    char * file_contents;        // 初步读取的文件内容--char

    try
    {
        // 只读模式打开文档
        read_file.Open(TxtFileLoad, CFile::modeRead | CFile::typeBinary);
        // 获取整个文件的字节长度--逻辑长度
        file_length = read_file.GetLength();
        // 创建字符串存储内容
        file_contents = new char[file_length + 2];
        memset(file_contents, 0, sizeof(char)*(file_length + 2));
        // 一次性读取整个文件
        read_file.Read(file_contents, sizeof(char)*file_length);
        // 文件末尾可能不会有\0(就是没有),所以加上结束符
        file_contents[file_length] = '\0';
        file_contents[file_length + 1] = '\0';
        // 关闭文件
        read_file.Close();
    }
    catch (CFileException *e)
    {
        CString read_errror_str;
        read_errror_str.Format(L"保存数据失败的原因是:%d", e->m_cause);
        MessageBox(read_errror_str);
        read_file.Abort();
        e->Delete();
        // 读取文件失败
        return false;
    }

    // 获取Txt文件编码格式(UTF-8BOM、ANSI、Unicode16-LE)
    WORD wFlag = 0;
    memcpy(&wFlag, file_contents, 2);

    //CString str;
    //str.Format(L"%X%X", LOBYTE(wFlag),HIBYTE(wFlag));
    //MessageBox(str);

    wchar_t* m_readTxt;                    // 存储转换后的Unicode16LE字符

    if (wFlag == 0xFEFF)                // Unicode16-LE
    {                                    // 摊牌--不干了
//        MessageBox(L"Unicode16-LE");
        //wchar_t* m_readTxt = (LPTSTR)file_contents;
        //m_readTxt[file_length / 2] = '\0';            // 不开空间,直接用原来的空间
        //TxtFileString = (CString)m_readTxt;
        m_readTxt = new wchar_t[file_length / 2 + 1];
        _tcscpy_s(m_readTxt, file_length / 2, (LPTSTR)file_contents + 1);            // 这个标志无法转,必须干掉
        m_readTxt[file_length / 2] = '\0';
        TxtFileString = (CString)m_readTxt;
    }
    else if(wFlag == 0xBBEF)            // UTF-8BOM   ?   UTF-8它不带标志。。需要根据其编码特征判断(有点麻烦
    {                // (wFlag == 0xBBEF || IsUTF8(file_contents + 3, file_length - 3))
//        MessageBox(L"UTF-8BOM");(LPCSTR)
        // int MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,                        \+
        // int cchMultiByte,LPWSTR lpWideCharStr,int cchWideChar);
        // 如果函数运行成功,并且cchMultiByte为0,返回值是待转换字符串的缓冲区所需求的宽字符数大小。
        // (此种情况用来获取转换所需的wchar_t的个数)
        int len = MultiByteToWideChar(CP_UTF8, NULL, file_contents + 3, file_length - 3, NULL, 0);
        //分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间
        m_readTxt = new wchar_t[len + 1];
        //转换 ------- file_contents + 3, file_length - 3 主要是去掉BOM的三个字节的标志
        MultiByteToWideChar(CP_UTF8, NULL, file_contents + 3, file_length - 3, m_readTxt, len);
        //最后加上'\0'
        m_readTxt[len] = '\0';
        //unicode版的MessageBox API
        TxtFileString = (CString)m_readTxt;
    }
    else if (IsUTF8(file_contents + 3, file_length - 3))
    {
        int len = MultiByteToWideChar(CP_UTF8, NULL, file_contents, file_length, NULL, 0);
        m_readTxt = new wchar_t[len + 1];
        MultiByteToWideChar(CP_UTF8, NULL, file_contents, file_length, m_readTxt, len);
        m_readTxt[len] = '\0';
        TxtFileString = (CString)m_readTxt;
    }
    else                                // ANSI   问题解决
    {
//        MessageBox(L"ANSI");
        int len = MultiByteToWideChar(CP_ACP, NULL, file_contents, file_length, NULL, 0);
        //分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间
        m_readTxt = new wchar_t[len + 1];
        //转换
        MultiByteToWideChar(CP_ACP, NULL, file_contents, file_length, m_readTxt, len);
        //最后加上'\0'
        m_readTxt[len] = '\0';
        TxtFileString = (CString)m_readTxt;
    }
    delete[] file_contents;
    delete[] m_readTxt;
    return true;
}

老规矩,第一部分,先打开文件,然后全部读取出来,这里要不要管编码格式问题呢?
不用,因为此处我们是使用char存下来的,不管你什么格式,在电脑中都是一个一个字节存下来的,现在的读取无非就是把这块内存拿了出来,
然后就是怎么判断属于哪一种编码格式?
有的编码格式会在头部加入标志,比如UTF-16-LE,UTF-8-BOM,但是Windows下的UTF-8和ANSI是没有标志的,暂且不管这两个家伙;
utf-8-BOM 前面有三个标志字节efbbbf       ,,,   unicode 标志头 fffe       当然这里还要看大端小端存储方式
这两个判断就方便多了,直接对比开头的字节,就知道是哪一个编码格式了,剩下的UTF-8和ANSI都没有标志,只能通过其字符编码特性来判断了,(这里百度查资料)(如何判断一个文本文件内容的编码格式 UTF-8 ? ANSI(GBK)

// 判断是否是UTF-8编码的Txt文本 --https://blog.csdn.net/jiangqin115/article/details/42684017
bool CTxt0721View::IsUTF8(const void* pBuffer, long size)
{
    bool IsUTF8 = true;
    unsigned char* start = (unsigned char*)pBuffer;
    unsigned char* end = (unsigned char*)pBuffer + size;
    while (start < end)
    {
        if (*start < 0x80) // (10000000): 值小于0x80的为ASCII字符
        {
            start++;
        }
        else if (*start < (0xC0)) // (11000000): 值介于0x80与0xC0之间的为无效UTF-8字符
        {
            IsUTF8 = false;
            break;
        }
        else if (*start < (0xE0)) // (11100000): 此范围内为2字节UTF-8字符
        {
            if (start >= end - 1)
            {
                break;
            }
            if ((start[1] & (0xC0)) != 0x80)
            {
                IsUTF8 = false;
                break;
            }
            start += 2;
        }
        else if (*start < (0xF0)) // (11110000): 此范围内为3字节UTF-8字符
        {
            if (start >= end - 2)
            {
                break;
            }
            if ((start[1] & (0xC0)) != 0x80 || (start[2] & (0xC0)) != 0x80)
            {
                IsUTF8 = false;
                break;
            }
            start += 3;
        }
        else
        {
            IsUTF8 = false;
            break;
        }
    }
    return IsUTF8;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值