解决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. 使用cstdiofile在vs2010中无法写入中文的问题

    在VC2010环境下, 以下代码无法实现使用CStdioFile向文本文件中写入中文(用notepad.exe查看不到写入的中文) CStdioFile file; file.Open(…); fil ...

  2. PHP往mysql数据库中写入中文失败

    该类问题解决办法就是 在建立数据库连接之后,将该连接的编码方式改为中文. 代码如下: $linkID=@mysql_connect("localhost","root&q ...

  3. 分享一个解决MySQL写入中文乱码的方法

    分享一个解决MySQL写入中文乱码的方法 之前有发帖请教过如何解决MySQL写入中文乱码的问题.但没人会,或者是会的人不想回答.搜索网上的答案并尝试很多次无效,所以当时就因为这个乱码问题搁浅了一个软件 ...

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

    file = open(filename,'a',encoding='utf8')#指定写入编码为utf8,否则写入中文会乱码

  5. jsp页面写入中文到mysql时出现了乱码(转)

    今天自己在用jsp把中文写入mysql的时候出现乱码,从数据库中读取出来的时候也显示为“??”,感觉应该出现了编码转换过程中的字符信息丢失.然后在mysql中直接执行该命令,发现中文是正常的,所有认为 ...

  6. Django的admin管理系统写入中文出错的解决方法/1267 Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation ‘locate’

    Django的admin管理系统写入中文出错的解决方法 解决错误: 1267  Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and ( ...

  7. MySQL写入中文乱码

    这点确实很迷,我的数据库属性确实设置了utf-8字符集,但写入中文还是乱码,后来是直接修改了全局配置才修改过来. 1.进入MySQL的本地安装路径,我的安装路径是"C:\Program Fi ...

  8. mysql 写入中文乱码

    今天从另一个系统往mysql数据库写入数据,发现中文变成了????? 检查数据库的设置 ,server对应字符集是latinl 调整mysql参数配置,配置文件目录/etc/mysql/mysql.c ...

  9. CStdioFile.WriteString无法向文件写入中文

    CStdioFile.WriteString向文件中写入字符串,但字符串中带有中文的,无法写入. 解决方案: 将带有中文的字符串进行转换后再写入文件. char* pBuffer = NULL; lo ...

随机推荐

  1. poj 2739 Sum of Consecutive Prime Numbers 素数 读题 难度:0

    Sum of Consecutive Prime Numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19697 ...

  2. 3: 组件间的依赖管理 Managing Dependencies Between Components Using the Prism Library 5.0 for WPF(英汉对照版)

    Applications based on the Prism Library are composite applications that potentially consist of many ...

  3. log4cpp单例类封装

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  4. django 自定义用户表替换系统默认表

    首先新建一个users应用,编写这个应用的models类. from django.contrib.auth.models import AbstractUser class UserProfile( ...

  5. iOS笔记之常用工具

    CocoaPods: 类库管理工具,使用教程见http://www.devtang.com/blog/2014/05/25/use-cocoapod-to-manage-ios-lib-depende ...

  6. 为什么叫金拱门- golden arch

    不要再纠结为什么叫这么难理解的名字了.因为从golden arch直译过来的撒.金色的拱门.就叫金拱门咯. 关于M的商标的历史来源如下: "McDonald's logo" red ...

  7. C语言动态库和静态库的使用及实践

    转自:https://www.cnblogs.com/CoderTian/p/5902154.html  1.C语言中的链接器 (1)每个 C 语言源文件被编译后生成目标文件,这些目标文件最终要被链接 ...

  8. Js/Jquery获取网页屏幕可见区域高度

    获取浏览器窗口的可视区域高度和宽度,滚动条高度有需要的朋友可参考一下. 1 document.body.clientWidth ==> BODY对象宽度 2 document.body.clie ...

  9. 用vue实现百度搜索功能

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Android Studio真机测试失败-----''No target device found" (转)

    参考文章: https://blog.csdn.net/chang_sir/article/details/51755572 今天想用真机测试一个程序,却报出这样一个Error"No tar ...