字符編碼真是個頭痛的問題,以前一直不放在心上,現在用到了才發現真的麻煩。
花了將近一天的時間終於達到目的。
測試環境VS2017+MYSQL8,各種編碼的具體說明就不講了,自行百度。
1、讀取數據亂碼問題:
vs項目下,默認編碼Unicode,但我的數據庫默認utf8,所以讀取數據的時候中文亂碼。
百度了一下,發現只要將utf8字符轉成unicode字符即可,轉換函數如下:
wchar_t* Utf8_2_Unicode(char* row_i)
{
int len = MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), NULL, 0);
wchar_t *wszStr = new wchar_t[len + 1];
MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), wszStr, len);
wszStr[len] = '\0';
return wszStr;
}
在函數外部定義一個wchar_t*類型變量接收返回值即可正確輸出。
2、寫入數據亂碼
解決了讀取出錯後以爲讀取只要反向轉換就行,但是把接收到的utf8字符轉換成unicode後並不能行。
然後在網上各種百度,然後又各種類型轉換編碼轉換人都弄暈了,總是圍繞utf8轉來轉去,沒有一點成效。
最後看了一個帖子,說要以gbk形式寫入,在內心抱着極度懷疑的情況下試了一下,沒想到竟然成功了。
其實這個帖子看了很多遍了,在心裏默默的排除了一萬遍沒想到最後竟然它纔是有用的。
方法很簡單,只要在寫入之前設置編碼爲gbk即可。
strcpy_s(sql, "set names gbk");
3、完整的測試代碼
#include "d:/include/mysql.h"
#include <iostream>
#include <windows.h>
#include <tchar.h>
using namespace std;
#pragma comment(lib, "d:/lib/libmysql.lib")
wchar_t* Utf8_2_Unicode(char* row_i)
{
int len = MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), NULL, 0);
wchar_t *wszStr = new wchar_t[len + 1];
MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), wszStr, len);
wszStr[len] = '\0';
return wszStr;
}
void showError(const char * error)
{
cout << error << endl;
getchar();
}
int main()
{
MYSQL mysql;
MYSQL *connect;
//初始化MYSQL
connect = mysql_init(&mysql);
if (connect == NULL)
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
cout << "Init OK" << endl;
//連接到MYSQL
connect = mysql_real_connect(connect, "localhost", "root", "123456", "mytest", 3306, NULL, 0);
if (connect == NULL)
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
cout << "Connect OK" << endl;
char sql[256] = {0};
//將編碼設置爲gbk
strcpy_s(sql, "set names gbk");
if (mysql_query(connect, sql))
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
//寫入中文數據
strcpy_s(sql, "INSERT INTO test(m1, m2) VALUES('測試', 'Test')");
if (mysql_query(connect, sql))
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
cout << "Insert success!\n";
//設置編碼格式utf8
strcpy_s(sql, "set names utf8");
int ret = mysql_query(connect, sql);
if (ret)
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
//讀取中文數據
strcpy_s(sql, "SELECT * FROM test");
ret = mysql_query(connect, sql);
if (ret)
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
else
{
//獲取結果集
MYSQL_RES *res = mysql_store_result(connect);
if (mysql_num_rows(res) == NULL)
{
showError(mysql_error(connect));
return mysql_errno(connect);
}
int nfieldNum = mysql_num_fields(res);
MYSQL_ROW row;
//取出結果集
while (row = mysql_fetch_row(res))
{
wchar_t *m1, *m2;
//將字符由utf8專轉爲unicode
m1 = Utf8_2_Unicode(row[0]);
m2 = Utf8_2_Unicode(row[1]);
MessageBox(NULL, m1, m2, NULL);
}
mysql_free_result(res);
}
mysql_close(connect);
getchar();
return 0;
}
在acl中直接下面這樣即可(寫的時候gbk,讀的時候utf8mb4):
// 連接池中最大連接數量限制
int dblimit = 10;
// 創建數據庫連接池對象
acl::mysql_conf dbconf(dbip_.c_str(), dbname_.c_str());
dbconf.set_dbuser(dbuser_.c_str()).set_dbpass(dbpwd_.c_str()).set_dblimit(dblimit);
dbconf.set_charset("gbk");
在acl每個寫入語句前用set names測試,聯合workbench查詢中的幾個測試:
acl中用gbk寫入成功,讀取用utf8mb4無亂碼也成功;
acl中用utf8mb4寫入直接報錯。