zoukankan      html  css  js  c++  java
  • 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里申请的。

      

      

  • 相关阅读:
    第八章 多线程编程
    Linked List Cycle II
    Swap Nodes in Pairs
    Container With Most Water
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock II
    Linked List Cycle
    4Sum
    3Sum
    Integer to Roman
  • 原文地址:https://www.cnblogs.com/rolling-stone/p/3373322.html
Copyright © 2011-2022 走看看