• 记录MFC在UNICODE字符集下读取中ANSI英文混合文件英文字符为单数汉字出现乱码问题


      惭愧,做了3年多 C++ 了,虽说半路出家,之前也做过 Linux 一年多,但是 MFC 也做了一年多了,由于一直维护公司的老项目,也没有做过新东西。

      最近心血来潮,在网上找了些学习视频,复习下 MFC 控件的使用,熟悉下 MFC 的 API,毕竟是吃饭的家伙,废话不多说,来干货。

      最近在仿写一个记事本软件,初具基本功能,但遇到了一个比较蹩脚的问题,MFC 在 UNICODE 字符集下在读取 ANSI 编码的文本文件时,全中文没问题,全英文也没问题,但是中英文混合时,当英文个数为奇数个时,英文后面的汉字就会编程乱码。

      原因是我想的太简单了,觉得读取 ANSI 编码的文本文件,就是读取多字节字符串,也就有了如下代码:

      代码中的形参只是定义了一个 CFile 对象并以只读方式打开,个人习惯,如果解释就要解释的明明白白,所以给这两句代码也复制过来了。

      CFile file;
      file.Open(szFile, CFile::modeRead);

     1 void CNotepadDlg::ReadAnsi(CFile& file)
     2 {
     3     file.Seek(0, CFile::begin);
     4     char buff[1024];
     5     UINT nRet = 0;
     6     CString str;
     7 
     8     while (nRet = file.Read(buff, sizeof(buff - 1)))
     9     {
    10         buff[nRet] = '';
    11         str += buff;
    12     }
    13 
    14     SetDlgItemText(IDC_EDIT_TEXT, str);
    15 
    16 }

      这只是按照单字节读取,当然显示也就存在问题。

      这是用微软记事本打开的 ANSI 编码的文本文档。

       这是我仿写记事本打开的文本文档

      结果很明显,不对。

      网上也找了很多处理办法,A2T,bstr_t,_tsetlocale(LC_ALL, _T("chs")); 这几个方法都试了,可能我水平不济,确实没弄明白,最后还是用最原始的 MultiByteToWideChar() 解决了问题。当然,代码还存在许多问题,待优化。

      

     1 void CMFC194Dlg::ReadAnsi(CFile& file)
     2 {
     3     file.Seek(0, CFile::begin);
     4     // TODO: 在此处添加实现代码.
     5     char buff[1024];
     6     UINT nRet = 0;
     7     CString str;
     8     
     9     LONGLONG nLen = file.GetLength();
    10     char* p = new char[nLen + 1];
    11     nLen = file.Read(p, nLen);
    12     p[nLen] = '';
    13     TCHAR* pText = new TCHAR[nLen + 2];
    14     memset(pText,0 , nLen + 2);
    15 
    16     nLen = MultiByteToWideChar(CP_ACP, NULL, p, -1, pText, nLen + 2);
    17 
    18     SetDlgItemText(IDC_EDIT_TEXT, pText);
    19 
    20     delete[]p;
    21     delete[]pText;
    22 }

      读取结果:

      处理这个问题的灵魂是这两句代码:

      TCHAR* pText = new TCHAR[nLen + 2];

      memset(pText,0 , nLen + 2);

      因为 ANSI 编码中英文字母占一个字节,中文汉字占两个字节,所以定义 pText 长度不能是 多字节长度 / 2 + 2,这会导致空间不足,使 MultiByteToWideChar() 返回 0,用 GetLastError() 可知返回122。

  • 相关阅读:
    SpringBoot2.0之一 新建项目helloWorld
    spring boot 的maven设置阿里云仓库
    新建SpringBoot项目运行页面报错Whitelabel Error Page This application has no explicit mapping for /error, so yo
    SpringBoot2.0 最简单的 idea 快速创建项目
    postgresql 按日期范围查询
    postgreSQL 应用case when的例子
    PostgreSQL 数据库NULL值的默认排序行为与查询、索引定义规范
    ASP.NET中在不同的子域中共享Session
    YKCW6-BPFPF-BT8C9-7DCTH-QXGWCYQ7PR-QTHDM-HCBCV-9GKGG-TB2TM
    Asp.net中基于Forms验证的角色验证授权
  • 原文地址:https://www.cnblogs.com/SmallAndGreat/p/12194651.html
Copyright © 2020-2023  润新知