• 2007-09-21

    CStdioFile在UNICODE环境下读取文本行〔转〕 - [Windows]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://zongtongyi.blogbus.com/logs/8372306.html

    CStdioFile file;
        if (!file.Open(m_File_Path, CFile::modeRead)) return;
        CString strLine;

        while (file.ReadString(strLine))   
        {
           //strLine处理
        }

    问题:
        CStdioFile在_MSBC环境下读取任何ANSI文本数据都没问题,在UNICODE环境下读取ANSI文本中的中文时就会显示乱码。

    原因:
        CStdioFile读取ANSI文本数据时按char类型读取,在_MSBC下可以直接填充到CString,在UNICODE环境下要先将char转 换成宽字符WCHAR,然后再填充到CString,即一个汉字的两个char将变成两个UNICODE字符WCHAR。

    解决办法:
        在UNICODE环境下file.ReadString(strLine)取得的数据实际上是char类型,但是存储在UNICODE字符串中。为了取得真实数据,必须对strLine进行处理。

    void function(CString &str)
    {
        char *szBuf = new char[str.GetLength()];

        for (int i = 0 ; i < str.GetLength(); i++)
        {
            szBuf[i] = str.GetAt(i);
        }
        CharToUnicode(szBuf , &str);

        delete []szBuf;
    }
        注:此函数在编译的时候会提示
                    warning C4244: '=' : conversion from 'unsigned short' to 'char', possible loss of data
                不用管它,丢失的数据是我们不需要的。


    ===================================================================================

    /////////////////////////////////////////////////////////////////////////////////////////
    // 将Char型字符转换为Unicode字符
    int CharToUnicode(char *pchIn, CString *pstrOut)
    {
        int nLen;
        WCHAR *ptch;

        if(pchIn == NULL)
        {
            return 0;
        }

        nLen = MultiByteToWideChar(CP_ACP, 0, pchIn, -1, NULL, 0);
        ptch = new WCHAR[nLen];
        MultiByteToWideChar(CP_ACP, 0, pchIn, -1, ptch, nLen);
        pstrOut->Format(_T("%s"), ptch);
       
        delete [] ptch;

        return nLen;
    }


    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 将Unicode字符转换为Char型字符
    int UnicodeToChar(CString &strIn, char *pchOut, int nCharLen)
    {
        if(pchOut == NULL)
        {
            return 0;
        }

        int nLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)strIn.GetBuffer(BUFFER_SIZE_KILO),-1, NULL, 0, NULL, NULL);
        nLen = min(nLen, nCharLen);
        WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)strIn.GetBuffer(BUFFER_SIZE_KILO), -1, pchOut,
            nLen, NULL, NULL);
       
        if(nLen < nCharLen)
        {
            pchOut[nLen] = 0;
        }

        return nLen;
    }

    历史上的今天:


    收藏到:Del.icio.us




    评论

  • szBuf[i] = 0;才是关键
    是因为C/C++字符串是必须以NULL即"\0"结尾的,"\0"的AscII码值是0
    必须加上,比如strlen(LPCSTR)取得字符串长度,如何取得?就是查找\0
    但是CString是封装过的,所以它其实是把整个串空间长度-1,因为最后一个是\0结束标志,CString没算在有效字符长度内,那么我们在操作char,WCHAR数组的时候就不能这样了,计算长度还是要吧\0算进去的,不然就越界了,而且\0结尾是要自己添加的,不然会使用strlen,strcpy就有可能非法操作,更可能堆栈溢出
    楼主也是一时没有考虑到这个问题,我找了很久才想起来,
  • 不错,不错,这个解决方案很管用。
    实际上,结尾会出现乱码原因是
    char *szBuf = new char[str.GetLength()];
    这句中str.GetLength()返回大小的问题,它按WCHAR字节大小,恰好是szBuf 所需大小的2倍
  • Thanks
  • 刚刚查了一下
    楼上的的代码要改一下啦
    char *szBuf = new char[str.GetLength()+1];

    for (int i = 0 ; i < str.GetLength(); i++)
    {
    szBuf[i] = str.GetAt(i);
    }
    szBuf[i] = 0;

    这样就OK了。。。
    赫赫
  • 为什么要“+1”?
    赫赫,我是照楼主的方法做的
    处理中文时没问题的
    但在字符串末尾有乱码
  • char *szBuf = new char[str.GetLength()+1];

    for (int i = 0 ; i < str.GetLength()+1; i++)

    否则还是乱码。