【数据库】SQLite3 中文存储

SQLite3中文

1. C语言宽字符

C95 开始,C语言提供 <wchar.h><wctype.h> 用于处理宽字符wide characters )。宽字符类型为 wchar_tchar 类型有的操作函数,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数据库中无法正常显示。
相关推荐
2601_951644323 小时前
C语言二级备考指南
c语言·编程基础·编译环境·二级考试·题库选择
777VG4 小时前
PostgreSQL +martin将多张表输出成一个 MVT
前端·数据库·postgresql
aax12134535 小时前
VOC 集群治理工程实操|美丽蓝天绿岛项目 RTO 工艺选型、管控方案与申报要
大数据·数据库·人工智能
IvorySQL5 小时前
PG 日报|优化缓冲区批量扫描,降低多套接字并发竞争
数据库·人工智能·postgresql·开源·区块链
这个DBA有点耶5 小时前
交易型数据库是什么?OLTP核心能力与2026选型指南
数据库·数据仓库·sql·database·数据库架构·olap·dba
大熊猫侯佩5 小时前
WWDC26 全新 SwiftData 的 .codable 宏选项:它不是泛型专用胶水
数据库·swift·apple
童谣18 小时前
越华环保集团市级统筹申报数字化中台:政策校验与减排仿真一体化架构
数据库·架构
制造数据与AI践行者老蒋8 小时前
离谱!PromptTemplate 遇上 JSON,花括号直接引发解析战争
数据库·microsoft·json
中微极客8 小时前
用LangChain 0.3构建生产级RAG与Agent:从API集成到Streamlit部署
数据库·人工智能·langchain
日拱一卒——功不唐捐8 小时前
红黑树删除(C语言)
c语言·数据结构