解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
2009-12-01 23:11

以下代码文件以CStdioFile向无法向文本中写入中文(用notepad.exe查 看不到写入的中文)

CStdioFile file;

file.Open(…);

file.WriteString(_T("abc你好"));//只能写入abc

解决办法:

使用setlocale语句设定区域

#include <locale>//头文件
CStdioFile file;

file.Open(…);

char* old_locale = _strdup( setlocale(LC_CTYPE,NULL) );

setlocale( LC_CTYPE, "chs" );//设定

file.WriteString(_T("abc你好"));//正常写入

setlocale( LC_CTYPE, old_locale );

free( old_locale );//还原区域设定

简化处理可以仅使用语句setlocale( LC_CTYPE, "chs" )。

setlocale:
函数原形为:char *setlocale( int category, const char *locale );
头文件:<locale.h>
所支持的操作系统为:ANSI, Win 95, Win NT
对于简体中文可以使用如下设置:setlocale( LC_ALL, "chs" );
为什么一定要调用setlocale呢?
因为在C/C++语言标准中定义了其运行时的字符集环境为"C",也就是ASCII字符集的一个子集,那么mbstowcs在工作时会将cstr中所包含 的字符串看作是ASCII编码的字符,而不认为是一个包含有chs编码的字符串,所以他会将每一个中文拆成2个ASCII编码进行转换,这样得到的结果就 是会形成4个wchar_t的字符组成的串,那么如何才能够让mbstowcs正常工作呢?在调用mbstowcs进行转换之间必须明确的告诉 mbstowcs目前cstr串中包含的是chs编码的字符串,通过setlocale( LC_ALL, "chs" )函数调用来完成,需要注意的是这个函数会改变整个应用程序的字符集编码方式,必须要通过重新调用setlocale( LC_ALL, "C" )函数来还原,这样就可以保证mbstowcs在转换时将cstr中的串看作是中文串,并且转换成为2个wchar_t字符,而不是4个。

本地化设置需要具备三个条件:
a. 语言代码 (Language Code)
b. 国家代码 (Country Code)
c. 编码(Encoding)
本地名字可以用下面这些部分来构造:
语言代码_国家代码.编码 比如(zh_CN.UTF-8, en_US等)

locale的别名表见 /usr/lib/X11/locale/locale.alias(以Debian GNU/Linux为例)
setlocale语言字符串参考

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ALENTAM/archive/2008/04/11/2281121.aspx

另外还有一种方法就是重新写CStdioFile的派生类CStdioFileEx(网上有)。

//好像C++中没有类能够读些Unicode格式的文本文件,所以我写了下面这个类。用法很简单,大家尝试几下就明白了。

#pragma once

class CStdioFileEx: public CStdioFile
{
public:
CStdioFileEx();
CStdioFileEx( LPCTSTR lpszFileName, UINT nOpenFlags );

virtual BOOL Open( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL );
virtual BOOL ReadString(CString& rString);
BOOL ReadWideString(CStringW& rString);
BOOL ReadAnsiString(CStringA& rString);
virtual void WriteString(LPCTSTR lpsz);
void WriteWideString(LPCWSTR lpsz);
void WriteAnsiString(LPCSTR lpsz);
bool IsUnicodeFormat() {return m_bIsUnicodeText;}
unsigned long GetCharCount();

// Additional flag to allow Unicode text format writing
enum {modeWriteUnicode = 0x100000};

static bool IsFileUnicode(const CString& sFilePath);

protected:
UINT PreprocessFlags(const CString& sFilePath, UINT& nOpenFlags);

bool    m_bIsUnicodeText;
};

//。cpp文件
#include "stdafx.h"
#include "StdioFileEx.h"

//在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,
//所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。这样
//如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。
//因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
//UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是
//EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
//Windows就是使用BOM来标记文本文件的编码方式的。
//有些老的浏览器和文本编辑器不支持BOM。
#define UNICODE_BOM        0xFEFF//Unicode "byte order mark" which goes at start of file

CStdioFileEx::CStdioFileEx(): CStdioFile()
{
m_bIsUnicodeText = false;
}

CStdioFileEx::CStdioFileEx(LPCTSTR lpszFileName,UINT nOpenFlags)
:CStdioFile(lpszFileName, PreprocessFlags(lpszFileName, nOpenFlags))
{
}

BOOL CStdioFileEx::Open(LPCTSTR lpszFileName,UINT nOpenFlags,CFileException* pError /*=NULL*/)
{
PreprocessFlags(lpszFileName, nOpenFlags);

return CStdioFile::Open(lpszFileName, nOpenFlags, pError);
}

BOOL CStdioFileEx::ReadString(CString& rString)
{
#ifdef _UNICODE
return ReadWideString(rString);
#else
return ReadAnsiString(rString);
#endif
}

BOOL CStdioFileEx::ReadWideString(CStringW& rString)
{
_ASSERTE(m_pStream);
rString = L"";      // empty string without deallocating

if(m_bIsUnicodeText)
{
    // If at position 0, discard byte-order mark before reading
    if(GetPosition() == 0)
    {
     wchar_t bom;
     Read(&bom, sizeof(wchar_t));
    }
    const int nMaxSize = 128;
    LPWSTR lpsz = rString.GetBuffer(nMaxSize);
    LPWSTR lpszResult;
    int nLen = 0;
    for (;;)
    {
     lpszResult = fgetws(lpsz, nMaxSize+1, m_pStream);
     rString.ReleaseBuffer();

// handle error/eof case
     if (lpszResult == NULL && !feof(m_pStream))
     {
      Afx_clearerr_s(m_pStream);
      AfxThrowFileException(CFileException::genericException, _doserrno,
       m_strFileName);
     }

// if string is read completely or EOF
     if (lpszResult == NULL ||
      (nLen = (int)lstrlenW(lpsz)) < nMaxSize ||
      lpsz[nLen-1] == '/n')
      break;

nLen = rString.GetLength();
     lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
    }
    //remove crlf if exist.
    nLen = rString.GetLength();
    if (nLen > 1 && rString.Mid(nLen-2) == L"/r/n")
    {
     rString.GetBufferSetLength(nLen-2);
    }
    return rString.GetLength() > 0;
}
else
{
    CStringA ansiString;
    BOOL bRetval = ReadAnsiString(ansiString);
    //setlocale(LC_ALL, "chs_chn.936");//no need
    rString = ansiString;
    return bRetval;
}
}

BOOL CStdioFileEx::ReadAnsiString(CStringA& rString)
{
_ASSERTE(m_pStream);
rString = "";      // empty string without deallocating

if(!m_bIsUnicodeText)
{
    const int nMaxSize = 128;
    LPSTR lpsz = rString.GetBuffer(nMaxSize);
    LPSTR lpszResult;
    int nLen = 0;
    for (;;)
    {
     lpszResult = fgets(lpsz, nMaxSize+1, m_pStream);
     rString.ReleaseBuffer();

// handle error/eof case
     if (lpszResult == NULL && !feof(m_pStream))
     {
      Afx_clearerr_s(m_pStream);
      AfxThrowFileException(CFileException::genericException, _doserrno,
       m_strFileName);
     }

// if string is read completely or EOF
     if (lpszResult == NULL ||
      (nLen = (int)lstrlenA(lpsz)) < nMaxSize ||
      lpsz[nLen-1] == '/n')
      break;

nLen = rString.GetLength();
     lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
    }
    //remove crlf if exist.
    nLen = rString.GetLength();
    if (nLen > 1 && rString.Mid(nLen-2) == "/r/n")
    {
     rString.GetBufferSetLength(nLen-2);
    }
    return rString.GetLength() > 0;
}
else
{
    CStringW wideString;
    BOOL bRetval = ReadWideString(wideString);
    //setlocale(LC_ALL, "chs_chn.936");//no need
    rString = wideString;
    return bRetval;
}
}

// Purpose:    Writes string to file either in Unicode or multibyte, depending on whether the caller specified the
//       CStdioFileEx::modeWriteUnicode flag. Override of base class function.
void CStdioFileEx::WriteString(LPCTSTR lpsz)
{
#ifdef _UNICODE
WriteWideString(lpsz);
#else
WriteAnsiString(lpsz);
#endif
}

void CStdioFileEx::WriteWideString(LPCWSTR lpsz)
{
ASSERT(lpsz != NULL);

if (lpsz == NULL)
{
    AfxThrowInvalidArgException();
}
if(m_bIsUnicodeText)
{
    ASSERT(m_pStream != NULL);
    // If writing Unicode and at the start of the file, need to write byte mark
    if(GetPosition() == 0)
    {
     wchar_t cBOM = (wchar_t)UNICODE_BOM;
     CFile::Write(&cBOM, sizeof(wchar_t));
    }
    if (fputws(lpsz, m_pStream) == _TEOF)
     AfxThrowFileException(CFileException::diskFull, _doserrno, m_strFileName);
}
else
{
    USES_CONVERSION;
    WriteAnsiString(CW2A(lpsz));
}
}

void CStdioFileEx::WriteAnsiString(LPCSTR lpsz)
{
ASSERT(lpsz != NULL);

if (lpsz == NULL)
{
    AfxThrowInvalidArgException();
}
if(!m_bIsUnicodeText)
{
    ASSERT(m_pStream != NULL);
    if (fputs(lpsz, m_pStream) == _TEOF)
     AfxThrowFileException(CFileException::diskFull, _doserrno, m_strFileName);
}
else
{
    USES_CONVERSION;
    WriteWideString(CA2W(lpsz));
}
}

UINT CStdioFileEx::PreprocessFlags(const CString& sFilePath, UINT& nOpenFlags)
{
m_bIsUnicodeText = false;

// If we have writeUnicode we must have write or writeRead as well
if (nOpenFlags & CStdioFileEx::modeWriteUnicode)
{
    ASSERT(nOpenFlags & CFile::modeWrite || nOpenFlags & CFile::modeReadWrite);
    m_bIsUnicodeText = true;
}
// If reading in text mode and not creating...
else if (nOpenFlags & CFile::typeText && !(nOpenFlags & CFile::modeCreate) && !(nOpenFlags & CFile::modeWrite ))
{
    m_bIsUnicodeText = IsFileUnicode(sFilePath);
}

//如果要读写Unicode格式的文本文件, 必须切换到typeBinary方式, 因为这会影响fputws/fgetws的工作方式(具体情况参考MSDN)。
if (m_bIsUnicodeText)
{
    nOpenFlags &= ~(CFile::typeText);
    nOpenFlags |= CFile::typeBinary;
}

return nOpenFlags;
}

// Purpose:    Determines whether a file is Unicode by reading the first character and detecting
//       whether it's the Unicode byte marker.
bool CStdioFileEx::IsFileUnicode(const CString& sFilePath)
{
CFile      file;
wchar_t     cFirstChar;
CFileException exFile;

bool      bIsUnicode = false;
// Open file in binary mode and read first character
if (file.Open(sFilePath, CFile::typeBinary | CFile::modeRead, &exFile))
{
    // If byte is Unicode byte-order marker, let's say it's Unicode
    if (file.Read(&cFirstChar, sizeof(wchar_t)) > 0 && cFirstChar == (wchar_t)UNICODE_BOM)
    {
     bIsUnicode = true;
    }

file.Close();
}
else
{
    // Handle error here if you like
}

return bIsUnicode;
}

unsigned long CStdioFileEx::GetCharCount()
{
int      nCharSize;
unsigned long nByteCount, nCharCount = 0;

if (m_pStream)
{
    // Get size of chars in file
    nCharSize = m_bIsUnicodeText ? sizeof(wchar_t): sizeof(char);

// If Unicode, remove byte order mark from count
    nByteCount = (unsigned long)GetLength();

if (m_bIsUnicodeText)
    {
     nByteCount = nByteCount - sizeof(wchar_t);
    }

// Calc chars
    nCharCount = (nByteCount / nCharSize);
}

return nCharCount;
}

CStdioFile的Writestring无法写入中文的问题相关推荐

  1. opencv_python使用cv2.imread()读取中文路径,cv2.imwrite()把图片写入中文路径。

    opencv_python使用cv2.imread()读取中文路径,cv2.imwrite()把图片写入中文路径 定义函数: cv2_imread(path)代替cv2.imread() cv2_im ...

  2. python django mysql写入中文乱码_解决django 向mysql中写入中文字符出错的问题

    之前使用django+mysql建立的一个站点,发现向数据库中写入中文字符时总会报错,尝试了修改settings文件和更改数据表的字符集后仍不起作用.最后发现,在更改mysql的字符集后,需要重建数据 ...

  3. excel调用python编程-使用Python和xlwt向Excel文件中写入中文的实例

    sheet1.write(row_num,0,f) row_num = 1 book.save('demo.xls') 程序执行结果如下: grey@DESKTOP-3T80NPQ:/mnt/e/01 ...

  4. 易语言mysql乱码_分享一个解决MySQL写入中文乱码的方法

    [编程语言:易语言] 之前有发帖请教过如何解决MySQL写入中文乱码的问题.但没人会,或者是会的人不想回答.搜索网上的答案并尝试很多次无效,所以当时就因为这个乱码问题搁浅了一个软件很多日子. 直到昨天 ...

  5. python写入中文到文件乱码的问题

    file = open(filename,'a',encoding='utf8')#指定写入编码为utf8,否则写入中文会乱码 转载于:https://www.cnblogs.com/jzss/p/5 ...

  6. MFC - CStdioFile 读取txt文件UNICODE 中文异常

    MFC - CStdioFile 读取txt文件UNICODE 中文异常 参考文章: (1)MFC - CStdioFile 读取txt文件UNICODE 中文异常 (2)https://www.cn ...

  7. python3 文本处理_解决python3 写入中文文本查看为乱

    在python3中我们直接使用 f = open("file","w") 然后写入中文时,我们先关闭然后再查看,时没问题的,但是如果我们在文本里面查看会正常的, ...

  8. python写入中文json

    在做项目的过程中,有时候我们需要用json文件来直观的反应某种隐射关系. json的数据结构类似于词典(dict) 这里总结下最近在写入json的过程中遇到的问题: 1.读写文件 json的主要方法有 ...

  9. python ogr_解决python ogr shp字段写入中文乱码的问题

    首先,先确认一下你的字段值是不是乱码,如果是,按照以下方法: 我的字段值是来自于一个geojson字符串,我在对它解析时做了如下处理: properties = fea.get("prope ...

最新文章

  1. RDKit | 基于RDKit从分子中提取3D药效团特征
  2. 十天快速入门Python
  3. 诺基亚塞班系列最强回顾(搬运整理)
  4. Python:粘包问题
  5. Win10系列:VC++ Direct3D模板介绍1
  6. SQLServer 维护脚本分享(08)临时数据库(tempdb)
  7. python递归求13的n次方_Python题目:递归的简单题目,求阶乘,求n-m的累积和,求斐波那契...
  8. 用R和BioConductor进行基因芯片数据分析(三):计算median
  9. 软件测试计划与测试方案
  10. php mov格式转换,mov格式怎么转换成mp4 如何将mov转换成mp4
  11. 追男妙计 三招搞定!
  12. RHEL6: Server panicked in 'redirfs' module
  13. Burp Suite设置浏览器代理
  14. vue常用的时间、手机号等的格式化方法
  15. ubuntu18.04系统如何新建文档,并且把新建文档作为模板全局使用
  16. 做人做事,必须要搞清楚的9个顺序
  17. 马克•安德森:软件正在占领全世界
  18. linux系统搭建论坛,在Linux平台下搭建discuz论坛
  19. KLayout学习记录(一)
  20. Qt 生成pdf文件

热门文章

  1. Mysql视图和触发器
  2. 【信号处理】基于蚁群优化随机共振检测附matlab代码
  3. Git从库中移除已删除大文件
  4. centos7安装xterm_CentOS 7使用x-manager中Xstart最新工具报缺少xterm包错误
  5. js复制、粘贴完整实例代码
  6. Android 获取应用列表
  7. arcgis栅格缺值填补
  8. 数据分析-主成分分析流程(R语言)
  9. 正则表达式——环视(Lookaround)(几分钟学会环视)
  10. Google60款开源项目