文章目录
0.大体mysql中文背景知识
①window平台只能显示gbk格式的,GBK和GB2312是比较类似的,但是GBK用的编码比较多,这两个都是基于阿斯克码ASCII,不过它们是两个阿斯克码存储一个汉字,(高级语言用GBK)
②linux的ssh控制台只能显示utf的,1或2或3或4字节表示汉字,变长的字节数
③Unicode编码格式是固定的,windows中都只用两个字节触发,linux中用utf-32 UCS-4
④vs2015之前,默认使用GBK
⑤qtcreator,默认使用utf-8
⑥vs2017默认utf-8
1.字符编码类型mysql设置和转换API分析
编码设置选择
①数据库编码可以设定
②表默认编码
③字段编码设置
转换API分析
转换方式一:STL
-
总体概况
-
额外涉及到的问题:
①2015-2017和2013和gcc兼容的版本不一样,不兼容
②gbk转码涉及到std::locate,std::locate使用的话涉及到本地的字符集,如果ubantu中没装中文,那么转码就会失败(环境依赖度非常高)
③但是只有一个平台就没问题
转换方式二:Windows
- 大体概况(MultiByteToWideChar多字节到宽字节的转换)
转换方式三:linux接口
- 注意:
linux中转换gbk,返回值不是字节数,还好可以通过strlen获取字节数也能解决这个问题
2.windows上字符集gbk和utf8互转 和linux上字符集GBK和UTF8互转
头文件
#ifdef _WIN32
#include <windows.h>
#else
#include <iconv.h>
#endif
#ifndef LXDATA_H
#define LXDATA_H
#ifdef _WIN32 //32 &64
#ifdef LXMYSQL_EXPORTS
//动态链接库项目调用
#define LXAPI __declspec(dllexport)
#else
//执行程序调用
#define LXAPI __declspec(dllimport)
#endif
#else //linux mac
#define LXAPI
#endif
#include <map>
#include <string>
#include <string.h>
namespace LX
{
enum LX_OPT {
LX_OPT_CONNECT_TIMEOUT,
LX_OPT_COMPRESS,
LX_OPT_NAMED_PIPE,
LX_INIT_COMMAND,
LX_READ_DEFAULT_FILE,
LX_READ_DEFAULT_GROUP,
LX_SET_CHARSET_DIR,
LX_SET_CHARSET_NAME,
LX_OPT_LOCAL_INFILE,
LX_OPT_PROTOCOL,
LX_SHARED_MEMORY_BASE_NAME,
LX_OPT_READ_TIMEOUT,
LX_OPT_WRITE_TIMEOUT,
LX_OPT_USE_RESULT,
LX_REPORT_DATA_TRUNCATION,
LX_OPT_RECONNECT,
LX_PLUGIN_DIR,
LX_DEFAULT_AUTH,
LX_OPT_BIND,
LX_OPT_SSL_KEY,
LX_OPT_SSL_CERT,
LX_OPT_SSL_CA,
LX_OPT_SSL_CAPATH,
LX_OPT_SSL_CIPHER,
LX_OPT_SSL_CRL,
LX_OPT_SSL_CRLPATH,
LX_OPT_CONNECT_ATTR_RESET,
LX_OPT_CONNECT_ATTR_ADD,
LX_OPT_CONNECT_ATTR_DELETE,
LX_SERVER_PUBLIC_KEY,
LX_ENABLE_CLEARTEXT_PLUGIN,
LX_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
LX_OPT_MAX_ALLOWED_PACKET,
LX_OPT_NET_BUFFER_LENGTH,
LX_OPT_TLS_VERSION,
LX_OPT_SSL_MODE,
LX_OPT_GET_SERVER_PUBLIC_KEY,
LX_OPT_RETRY_COUNT,
LX_OPT_OPTIONAL_RESULTSET_METADATA,
LX_OPT_SSL_FIPS_MODE
};
enum FIELD_TYPE {
LX_TYPE_DECIMAL,
LX_TYPE_TINY,
LX_TYPE_SHORT,
LX_TYPE_LONG,
LX_TYPE_FLOAT,
LX_TYPE_DOUBLE,
LX_TYPE_NULL,
LX_TYPE_TIMESTAMP,
LX_TYPE_LONGLONG,
LX_TYPE_INT24,
LX_TYPE_DATE,
LX_TYPE_TIME,
LX_TYPE_DATETIME,
LX_TYPE_YEAR,
LX_TYPE_NEWDATE, /**< Internal to MySQL. Not used in protocol */
LX_TYPE_VARCHAR,
LX_TYPE_BIT,
LX_TYPE_TIMESTAMP2,
LX_TYPE_DATETIME2, /**< Internal to MySQL. Not used in protocol */
LX_TYPE_TIME2, /**< Internal to MySQL. Not used in protocol */
LX_TYPE_JSON = 245,
LX_TYPE_NEWDECIMAL = 246,
LX_TYPE_ENUM = 247,
LX_TYPE_SET = 248,
LX_TYPE_TINY_BLOB = 249,
LX_TYPE_MEDIUM_BLOB = 250,
LX_TYPE_LONG_BLOB = 251,
LX_TYPE_BLOB = 252,
LX_TYPE_VAR_STRING = 253,
LX_TYPE_STRING = 254,
LX_TYPE_GEOMETRY = 255
} ;
struct LXAPI LXData
{
LXData(const char* data=0);
LXData(const int *d);
//读取文件,内容写入到data,size大小 ,会在堆中申请data的空间,需要用Drop释放
bool LoadFile(const char* filename);
bool SaveFile(const char * filename);
const char * data = 0;
int size = 0;
FIELD_TYPE type;
//释放LoadFile申请的data空间
void Drop();
std::string UTF8ToGBK();
std::string GBKToUTF8();
};
//插入和更新数据的数据结构
typedef std::map <std::string, LXData> XDATA;
}
#endif
gbk转utf-8
#ifndef _WIN32
static size_t Convert(char *from_cha, char *to_cha, char *in, size_t inlen, char *out, size_t outlen)
{
//转换上下文
iconv_t cd;
cd = iconv_open(to_cha, from_cha);
if (cd == 0)
return -1;
memset(out, 0, outlen);
char **pin = ∈
char **pout = &out;
//返回转换字节数的数量,但是转GBK时经常不正确 >=0就成功
size_t re = iconv(cd, pin, &inlen, pout, &outlen);
iconv_close(cd);
return re;
}
#endif
std::string LXData::GBKToUTF8()
{
string re = "";
#ifdef _WIN32
//GBK转unicode
//1.1 统计转换后字节数
int len = MultiByteToWideChar(CP_ACP, //转换的格式
0, //默认的转换方式
data, //输入的字节
-1, //输入的字符串大小 -1 找\0
0,//输出
0//输出的空间大小
);
if (len <= 0)
return re;
wstring udata;//获取的字符串用udata存储
udata.resize(len);//获取字符串的大小
MultiByteToWideChar(CP_ACP, 0, data, -1, (wchar_t*)udata.data(), len);
//2 unicode 转utf-8
len = WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)udata.data(), -1, 0, 0,
0, //失败默认替代字符,一但失败直接断掉了
0 //是否使用默认替代 ,0代表false
);
if (len <= 0)
return re;
re.resize(len);
WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)udata.data(), -1, (char*)re.data(), len, 0, 0);
#else
re.resize(1024);
int inlen = strlen(data);
Convert((char*)"gbk", (char*)"utf-8", (char*)data, inlen, (char*)re.data(), re.size());
int outlen = strlen(re.data());
re.resize(outlen);
#endif
return re;
}
utf-8转gbk
#ifndef _WIN32
static size_t Convert(char *from_cha, char *to_cha, char *in, size_t inlen, char *out, size_t outlen)
{
//转换上下文
iconv_t cd;
cd = iconv_open(to_cha, from_cha);
if (cd == 0)
return -1;
memset(out, 0, outlen);
char **pin = ∈
char **pout = &out;
//返回转换字节数的数量,但是转GBK时经常不正确 >=0就成功
size_t re = iconv(cd, pin, &inlen, pout, &outlen);
iconv_close(cd);
return re;
}
#endif
std::string LXData::UTF8ToGBK()
{
string re = "";
//1 UFT8 转为unicode win utf16
#ifdef _WIN32
//1.1 统计转换后字节数
int len = MultiByteToWideChar(CP_UTF8, //转换的格式
0, //默认的转换方式
data, //输入的字节
-1, //输入的字符串大小 -1 找\0结束
0,//输出
0//输出的空间大小
);
if (len <= 0)
return re;
wstring udata; //获取的字符串用udata存,这个出了作用域自动释放,不用自己释放
udata.resize(len); //获取的字符串用udata存
MultiByteToWideChar(CP_UTF8, 0, data, -1, (wchar_t*)udata.data(), len);
//2 unicode 转GBK
len = WideCharToMultiByte(CP_ACP, 0, (wchar_t*)udata.data(), -1, 0, 0,
0, //失败默认替代字符
0 //是否使用默认替代
);
if (len <= 0)
return re;
re.resize(len);
WideCharToMultiByte(CP_ACP, 0, (wchar_t*)udata.data(), -1, (char*)re.data(), len, 0, 0);
#else
re.resize(1024);
int inlen = strlen(data);
Convert((char*)"utf-8", (char*)"gbk", (char*)data, inlen, (char*)re.data(), re.size());
int outlen = strlen(re.data());
re.resize(outlen);
#endif
return re;
}
3.LXMysql库添加字符集转换函数并测试GBK
- 测试代码