解决Oracle中C语言乱码问题(c oracle乱码问题)
解决Oracle中C语言乱码问题
在Oracle数据库中,如果需要通过C语言程序连接、查询数据库,常常会遇到中文乱码的情况。本文将介绍如何解决Oracle中C语言乱码问题。
1. 设置NLS_LANG环境变量
在Oracle服务器或客户端操作系统上,需要设置NLS_LANG环境变量为相应的字符集。例如,如果Oracle数据库中使用的是UTF8字符集,则需要设置NLS_LANG为”AMERICAN_AMERICA.UTF8″。具体设置方式可以查找操作系统的相关资料,以下是Windows系统下设置NLS_LANG的方法:
– 打开“控制面板”-“系统”-“高级系统设置”-“环境变量”;
– 在“系统变量”或“用户变量”中新建或修改“NLS_LANG”变量,值为相应字符集;
2. 使用Unicode转换函数
在C语言程序中调用Oracle数据库时,可以使用Unicode转换函数将字符串转换为Unicode编码,避免中文乱码的情况。Oracle提供了多种Unicode转换函数,常用的有以下几种:
– OCILobCharSetToUnicode():将CLOB类型的字符串从指定字符集转换为Unicode编码;
– OCIUnicodeToChar():将Unicode编码转换为指定字符集;
– OCIUTF8ToWChar():将UTF8编码的字符串转换为Unicode编码。
以下是一个示例代码,演示如何使用OCILobCharSetToUnicode()函数将CLOB类型的字符串从GBK字符集转换为Unicode编码:
OCIError *errhp;
OCIEnv *envhp;
OCISvcCtx *svchp;
OCIStmt *stmthp;
OCILobLocator *lob;
int inLen, outLen, lobLen;
char *inStr = “测试”;
ub2 *outStr;
OCICharSet *srcCs, *dstCs;
uword csid;
// 初始化
envhp = NULL;
errhp = NULL;
svchp = NULL;
stmthp = NULL;
OCIEnvCreate(&envhp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
OCIHandleAlloc(envhp, &errhp, OCI_HTYPE_ERROR, 0, NULL);
OCIHandleAlloc(envhp, &svchp, OCI_HTYPE_SVCCTX, 0, NULL);
OCIHandleAlloc(envhp, &stmthp, OCI_HTYPE_STMT, 0, NULL);
// 连接数据库
OCILogon2(envhp, errhp, &svchp, “user”, strlen(“user”), “pass”, strlen(“pass”), “db”, strlen(“db”), OCI_DEFAULT);
OCIStmtPrepare(stmthp, errhp, “INSERT INTO lob_table (lob_col) VALUES (:1)”, strlen(“INSERT INTO lob_table (lob_col) VALUES (:1)”), OCI_NTV_SYNTAX, OCI_DEFAULT);
// 分配LOB
OCIDescriptorAlloc(envhp, &lob, OCI_DTYPE_LOB, 0, NULL);
// 设置字符集
srcCs = OCICharsetWithName(envhp, “GBK”);
dstCs = OCICharsetWithName(envhp, “AL32UTF8”);
csid = OCINlsCharSetNameToId(envhp, “AL32UTF8”);
OCIAttrSet(lob, OCI_DTYPE_LOB, &csid, 0, OCI_ATTR_CHARSET_ID, errhp);
// 插入数据
inLen = strlen(inStr);
OCILobWrite(svchp, errhp, lob, &inLen, 1, (dvoid*)inStr, strlen(inStr), OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
OCIStmtBindByPos(stmthp, &lob, sizeof(OCILobLocator*), OCI_BIND_IN, 1, OCI_DTYPE_LOB, NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
OCICommit(svchp, errhp, OCI_DEFAULT);
// 读取数据
OCIAttrGet(lob, OCI_DTYPE_LOB, &lobLen, 0, OCI_ATTR_LOB_LENGTH, errhp);
outLen = lobLen/2 + lobLen%2;
outStr = (ub2*)malloc(outLen * sizeof(ub2));
OCILobRead(svchp, errhp, lob, &lobLen, 1, (dvoid*)outStr, outLen, NULL, NULL, 0, SQLCS_IMPLICIT);
outStr[outLen-1] = L’\0′;
OCIUnicodeToChar(envhp, (char*)outStr, outLen*sizeof(ub2), dstCs, inLen, srcCs, &outLen);
// 释放资源
OCILogoff(svchp, errhp);
OCIHandleFree(errhp, OCI_HTYPE_ERROR);
OCIHandleFree(svchp, OCI_HTYPE_SVCCTX);
OCIHandleFree(stmthp, OCI_HTYPE_STMT);
OCIDescriptorFree(lob, OCI_DTYPE_LOB);
OCIEnvFree(envhp);
3. 使用NCHAR类型
在Oracle中,NCHAR类型是一种固定长度的Unicode字符类型,可以存储任何Unicode字符。如果需要在C语言程序中处理中文时避免乱码问题,可以将数据库表中的字符类型改为NCHAR类型,然后使用Unicode转换函数操作即可。
例如,如果有一个表mytable,其中有一个name字段需要存储中文,可以将该字段改为NCHAR类型:
ALTER TABLE mytable MODIFY (name NCHAR(10));
然后在C语言程序中使用OCILobWrite()函数写入数据:
OCIStmtPrepare(stmthp, errhp, “INSERT INTO mytable (name) VALUES (:1)”, strlen(“INSERT INTO mytable (name) VALUES (:1)”), OCI_NTV_SYNTAX, OCI_DEFAULT);
OCILobLocator *lob;
OCIDescriptorAlloc(envhp, &lob, OCI_DTYPE_LOB, 0, NULL);
int inLen = strlen(“测试”);
OCILobWrite(svchp, errhp, lob, &inLen, 1, (dvoid*)”测试”, inLen, OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
OCIStmtBindByPos(stmthp, &lob, sizeof(OCILobLocator*), OCI_BIND_IN, 1, OCI_DTYPE_LOB, NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
OCICommit(svchp, errhp, OCI_DEFAULT);
在读取数据时,可以使用OCIUnicodeToChar()函数将Unicode编码转换为指定字符集:
OCIStmtExecute(svchp, stmthp, errhp, 0, 0, NULL, NULL, OCI_DESCRIBE_ONLY);
int colNameLen;
OCIAttrGet(stmthp, OCI_HTYPE_STMT, &colNameLen, NULL, OCI_ATTR_PARAM_COUNT, errhp);
char colName[20];
ub2 ubuf[20];
OCIDefine *colNameDef;
OCIStmtFetch2(stmthp, errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
OCIAttrGet(stmthp, OCI_HTYPE_STMT, &colNameDef, NULL, OCI_ATTR_DESCRIBE_HANDLE, errhp);
OCIAttrGet(colNameDef, OCI_HTYPE_DESCRIBE, &colNameLen, NULL, OCI_ATTR_NAME, errhp);
OCIParamGet(colNameDef, OCI_DTYPE_PARAM, errhp, &colNameDef, 1);
OCIDefineByPos(stmthp, &colNameDef, errhp, 1, colName, sizeof(colName), SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT);
OCILobLocator *lob;
OCIDescriptorAlloc(envhp, &lob, OCI_DTYPE_LOB, 0, NULL);
OCIDefineByPos(stmthp, &lob, errhp, 2, NULL, 0, SQLT_BLOB, NULL, NULL, NULL, OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
while (OCIStmtFetch2(stmthp, errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT) == OCI_SUCCESS) {
OCILobLocator *lob;
OCIDescriptorAlloc(envhp, &lob, OCI_DTYPE_LOB, 0, NULL);
OCIDefineByPos(stmthp, &lob, errhp, 2, NULL, 0, SQLT_BLOB, NULL, NULL, NULL, OCI_DEFAULT);
OCIDefineByPos(stmthp, &colNameDef, errhp, 1, colName, sizeof(colName), SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT);
OCIStmtFetch2(stmthp, errhp, 1, OCI_FETCH_NEXT, 0, OCI