SQLite3中文
1. C语言宽字符
从C95 开始,C语言提供 <wchar.h>和<wctype.h> 用于处理宽字符 (wide characters )。宽字符类型为 wchar_t
。char
类型有的操作函数,wchar_t
都有对应的函数。
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <wchar.h>
int main(int argc, char *argv[]) {
unsigned index = 0;
char *name = "琉璃";
unsigned length = strlen(name);
printf("%s%lu%s\n",
"The size of data-type named 'char' is ",
sizeof(char),
" bytes");
printf("[%u]:%s(%lu bytes)\n",
length,
name,
sizeof(name));
for (index = 0; index < length; index++) {
printf("[%u]%d\n", index, name[index]);
}
setlocale(LC_CTYPE, "UTF-8"); /* 设置本地化编码 */
wchar_t *w_name = L"琉璃"; /* 宽字符串 */
length = wcslen(w_name); /* 获取宽字符串长度 */
printf("%s%lu%s\n",
"The size of data-type named 'wchar_t' is ",
sizeof(wchar_t),
" bytes");
wprintf(L"[%u]:%ls(%lu bytes)\n",
length,
w_name,
sizeof(w_name));
for (index = 0; index < length; index++) {
wprintf(L"[%u]%lc(U+%X)\n", index, w_name[index], w_name[index]);
}
return EXIT_SUCCESS;
}
/* The end of source file that is named 'main.c'. */
bash
The size of data-type named 'char' is 1 bytes
[6]:琉璃(8 bytes)
[0]-25
[1]-112
[2]-119
[3]-25
[4]-110
[5]-125
The size of data-type named 'wchar_t' is 4 bytes
[2]:琉璃(8 bytes)
[0]琉(U+7409)
[1]璃(U+7483)
由上可以看出如果使用 char
类型也能正常显示,可是长度和数据内容不能正常显示。而 wchar_t
可以解决这问题。
2. SQLite3宽字符
在SQLite3 中,字符串类型被称为 TEXT
类型,可以存储任意字符集的字符串数据,包括中文字符。SQLite3 默认使用UTF-8 编码来存储和处理 TEXT
类型数据,因此,可以存储和处理包括中文字符在内的多种字符集数据。
另外SQLite3 中还有一个类型为 BLOB
完全按照输入时的数据存储。
2.1 使用char类型存储
使用 char
存储UTF-8编码 的文本。代码如下:
SQLite3中有表:
sql
CREATE TABLE IF NOT EXISTS "COMPANY"(
ID INTEGER PRIMARY KEY,
NAME TEXT NOT NULL,
AGE INTEGER NOT NULL
);
c
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
void errorMsg(sqlite3 *db, const char *errStr);
int main(int argc, char *argv[]) {
char *filename = "database.db";
sqlite3 *db = NULL;
int rc = SQLITE_OK;
rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE, NULL);
if (rc != SQLITE_OK) {
errorMsg(db, "Can't open database");
rc = sqlite3_close_v2(db);
if (rc != SQLITE_OK) {
perror("Close database failure\n");
}
exit(EXIT_FAILURE);
}
sqlite3_stmt *stmt = NULL;
char *sql = "INSERT INTO COMPANY(NAME, AGE) VALUES(?,?)";
char *name = "琉璃";
printf("%s%lu\n",
"The size of 'char' is ", sizeof(char));
printf("name is %s(%lu bytes)\n",
name, sizeof(name));
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
rc = sqlite3_bind_text(stmt, 1, name, -1, NULL);
rc = sqlite3_bind_int(stmt, 2, 20);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
errorMsg(db, "Sqlite3 execute step failure");
}
rc = sqlite3_reset(stmt);
if (rc != SQLITE_OK) {
errorMsg(db, "Sqlite3 execute reset failure");
}
}
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK) {
errorMsg(db, "Destruct the object of the type is sqlite_stmt failure");
}
char *sql_2 = "SELECT * FROM COMPANY";
rc = sqlite3_prepare_v2(db, sql_2, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
int id = 0;
unsigned char *name = NULL;
int age = 0;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
id = sqlite3_column_int(stmt, 0);
name = (unsigned char*)sqlite3_column_text(stmt, 1);
age = sqlite3_column_int(stmt, 2);
printf("%s%d%s%s%s%d\n",
"ID = ", id,
" NAME = ", name,
" AGE = ", age);
}
}
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK) {
errorMsg(db, "Destruct the object of the type is sqlite_stmt failure");
}
rc = sqlite3_close_v2(db);
if (rc != SQLITE_OK) {
perror("Close database failure.\n");
}
return 0;
}
void errorMsg(sqlite3 *db, const char *errStr) {
fprintf(stderr, "%s[%d]: %s\n",
errStr,
sqlite3_errcode(db),
sqlite3_errmsg(db));
}
bash
The size of 'char' is 1
name is 琉璃(8 bytes)
ID = 1 NAME = 琉璃 AGE = 20
ID = 2 NAME = 琉璃 AGE = 20
$ sqlite3 database.db
SQLite version 3.43.2 2023-10-10 13:08:14
Enter ".help" for usage hints.
sqlite> SELECT * FROM COMPANY;
1|琉璃|20
2|琉璃|20
sqlite>
优点:
- C语言代码少,在SQLite3中也能正常显示。
缺点:
- 无法正确的操作
char *
中的UTF-8编码。
2.2 使用wchar_t类型存储
在SQLite3中没有 wchar_t
类型的存储函数。但有 BLOB
类型的存储函数。
c
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
其中存储类型为 void *
类型,所以所有类型都可原样存储。
SQLite3中有表:
sql
CREATE TABLE IF NOT EXISTS "COMPANY_BLOB" (
ID INTEGER PRIMARY KEY,
NAME BLOB NOT NULL,
AGE INTEGER NOT NULL
);
代码如下:
c
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
#include <sqlite3.h>
void errorMsg(sqlite3 *db, const char *errStr);
int main(int argc, char *argv[]) {
char *filename = "database.db";
sqlite3 *db = NULL;
int rc = SQLITE_OK;
rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE, NULL);
if (rc != SQLITE_OK) {
errorMsg(db, "Can't open database");
rc = sqlite3_close_v2(db);
if (rc != SQLITE_OK) {
perror("Close database failure\n");
}
exit(EXIT_FAILURE);
}
sqlite3_stmt *stmt = NULL;
setlocale(LC_CTYPE, "UTF-8");
char *sql_3 = "INSERT INTO COMPANY_BLOB (NAME, AGE) VALUES (?,?)";
wchar_t *w_name = L"琉璃";
printf("%s%lu\n",
"The size of 'wchar_t' is ", sizeof(wchar_t));
wprintf(L"w_name is %ls(%lu bytes)\n",
w_name, sizeof(w_name));
rc = sqlite3_prepare_v2(db, sql_3, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
rc = sqlite3_bind_blob(stmt, 1, w_name, sizeof(w_name) + 1, NULL);
rc = sqlite3_bind_int(stmt, 2, 20);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
errorMsg(db, "Sqlite3 execute step failure");
}
rc = sqlite3_reset(stmt);
if (rc != SQLITE_OK) {
errorMsg(db, "Sqlite3 execute reset failure");
}
}
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK) {
errorMsg(db, "Destruct the object of the type is sqlite_stmt failure");
}
char *sql_4 = "SELECT * FROM COMPANY_BLOB";
rc = sqlite3_prepare_v2(db, sql_4, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
int id = 0;
wchar_t *name = NULL;
int age = 0;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
id = sqlite3_column_int(stmt, 0);
name = (wchar_t*)sqlite3_column_blob(stmt, 1);
age = sqlite3_column_int(stmt, 2);
wprintf(L"%s%d%s%ls%s%d\n",
"ID = ", id,
" NAME = ", name,
" AGE = ", age);
}
}
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK) {
errorMsg(db, "Destruct the object of the type is sqlite_stmt failure");
}
rc = sqlite3_close_v2(db);
if (rc != SQLITE_OK) {
perror("Close database failure.\n");
}
return 0;
}
void errorMsg(sqlite3 *db, const char *errStr) {
fprintf(stderr, "%s[%d]: %s\n",
errStr,
sqlite3_errcode(db),
sqlite3_errmsg(db));
}
bash
The size of 'wchar_t' is 4
w_name is 琉璃(8 bytes)
ID = 1 NAME = 琉璃 AGE = 20
ID = 2 NAME = 琉璃 AGE = 20
$ sqlite3 database.db
SQLite version 3.43.2 2023-10-10 13:08:14
Enter ".help" for usage hints.
sqlite> SELECT * FROM COMPANY_BLOB;
1| t|20
2| t|20
优点:
- C语言编码中
wchar_t
类型可以正确的操作UTF-8编码。
缺点:
- SQLite数据库中无法正常显示。