• VS下用c++连接mysql,字符编码格式转换


    这两天在VS2010下用c++连接mysql数据库,开始的时候能成功读取数据库中的INT型数据,但对其中的varchar类型无法正常读取(数据库采用utf-8编码),读取出来的都是乱码。后来经过在网上搜索和思考,终于解决了。整理如下。

    问题解析:mysql中是用utf-8格式存储字符串,而VS中是用ANSI(文件-高级保存选项,可以看到,中文操作系统的默认代码页为GB2312,即ANSI的一个代码页20936),所以在二者之间需要进行转换。核心是利用两个函数:MultiByteToWideChar和WideCharToMultiByte

    参照博文http://blog.csdn.net/waden/article/details/6125471和博文http://www.cnblogs.com/wind-net/archive/2012/10/31/2718329.html,代码如下:

    #include "stdafx.h"
    #include <Windows.h>
    #include <string>
    
    /*
      功能:将UTF8格式的字符转换为ANSI格式
      返回值 1:成功
            0:失败
    */
    bool UTF82ANSI(const char* pIn, std::string& strOut)
    {
    	// UTF8转换为宽字符wchar_t
    	DWORD dwNum = MultiByteToWideChar(CP_UTF8,NULL ,pIn,-1, NULL, 0);
    	wchar_t* pUnicode = new wchar_t[dwNum + 1];
    	memset(pUnicode, 0, dwNum * sizeof(wchar_t));
    	int ret1 = MultiByteToWideChar(CP_UTF8,NULL ,pIn,-1, pUnicode, dwNum);
    
    	//宽字符转换为ANSI
    	dwNum = WideCharToMultiByte(CP_OEMCP,NULL,pUnicode,-1,NULL,0,NULL,FALSE);
    	char *pOut = new char[dwNum + 1];
    	int ret2 = WideCharToMultiByte (CP_OEMCP,NULL,pUnicode,-1,pOut,dwNum,NULL,FALSE);
    	*(pOut + dwNum) = '';
    	strOut = pOut;
    
    	//释放空间
    	delete[] pUnicode;
    	pUnicode = NULL;
    	delete[] pOut;
    	pOut = NULL;
    
    	return ((ret1 != 0) && (ret2 != 0));
    }
    
    /*
      功能:将ANSI格式的字符转换为UTF8格式
      返回值 1:成功
             0:失败
    */
    bool ANSI2UTF8(const char* pIn, char*& pOut)
    {
    	// ANSI转换为宽字符wchar_t
    	int len = strlen(pIn);
    	DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, pIn, len, NULL, 0);  
    	wchar_t* pUnicode = new wchar_t[dwNum+1];  
    	memset(pUnicode, 0, (dwNum+1)*sizeof(wchar_t));  
    	int ret1 = MultiByteToWideChar(CP_ACP, 0, pIn, len, pUnicode, dwNum);  
    
    	// 宽字符wchar_t转换为UTF8
    	dwNum = WideCharToMultiByte(CP_UTF8,NULL,pUnicode,-1,NULL,0,NULL,FALSE);  
    	pOut = new char[dwNum + 1]; 
    	memset(pOut, 0, sizeof(char)*(dwNum + 1));
    	int ret2 = WideCharToMultiByte (CP_UTF8,NULL,pUnicode,-1,pOut,dwNum,NULL,FALSE);  
    	*(pOut + dwNum) = '';  
    	  
    	delete[] pUnicode;
    	pUnicode = NULL;
    
    	return ((ret1 != 0) && (ret2 != 0));  
    }
    

      

    核心都是通过宽字符wchar_t作为中间的过渡。

    值得指出的是,在函数UTF82ANSI中,欲转换的字符pIn必须是char*型的,而不能是string型的。因为若是string型的,你传入实参的时候就相当于用了ANSI编码方式去识别utf-8编码的字符,结果导致string类型里面存的内容就已经是乱码了,后面不管怎么转换都没用。博文http://www.cnblogs.com/wind-net/archive/2012/10/31/2718329.html里面就犯了这样的错误。同理,函数ANSI2UTF8中,转换后输出的字符pOut也必须是char*型的,否则若是string型,则系统又默认其为ANSI格式,变为乱码,这样再给mysql数据库用,数据库会试图用utf-8编码方式去识别ANSI格式编码的字符,又会出现错误。

    有了上述转换函数后,就可以成功在mysql中插入和读取数据了,之前记得设置连接数据库的编码方式,如下:

    con->setClientOption("characterSetResults", "utf8"); 

    之后,就可以读取数据了(从数据库中读取utf-8格式字符,转换为ANSI格式显示):

    stmt = con->createStatement();  
    res = stmt->executeQuery("SELECT * from user");  
    while (res->next())   
    {  
    	string name;
    	if( UTF82ANSI(res->getString("NAME").c_str(), name ) == true)
    	{
    		cout<<name<<endl;
    	}
    			
    } 
    delete res;  
    delete stmt; 

    注意,传入参数必须是是char*型的,否则传入时就会变成乱码。

    写入数据(将ANSI格式字符写入到utf-8编码的数据库里):

    pstmt = con->prepareStatement("INSERT INTO user(ID,NAME) VALUES (?,?)");
    string name = "一二三四   五六七八";
    char* name_UTF8 = NULL;
    if( ANSI2UTF8(name.c_str(), name_UTF8) ==  true )
    {
    	pstmt->setInt(1,15);
    	pstmt->setString(2,name_UTF8);
    	pstmt->executeUpdate();
    }
    delete[] name_UTF8;
    name_UTF8 = NULL;
    delete pstmt;

    注意:(1)函数传出参数(也即setString的传入参数)必须是char*型的,否则会出现乱码;(2)记得释放name_UTF8的内存,它的内存是在函数ANSI2UTF8里申请的。

      

      

  • 相关阅读:
    向量杂谈
    对widget使用WM_SetCallback
    群延迟与广义线性相位
    采样的频域表示
    Oracle 表的连接方式(2)-----HASH JOIN的基本机制1
    Oracle 表的连接方式(1)-----Nested loop join和 Sort merge join
    Oracle 表的访问方式(2)-----索引扫描
    Oracle 表的访问方式(1) ---全表扫描、通过ROWID访问表
    11g RAC R2 之Linux DNS 配置
    11g RAC r2 的启停命令概述1
  • 原文地址:https://www.cnblogs.com/rolling-stone/p/3373322.html
Copyright © 2020-2023  润新知