L
O
A
D
I
N
G

VS 配置 SQLite3 库


〇、前言

What Is SQLite?

SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. SQLite is the most used database engine in the world. SQLite is built into all mobile phones and most computers and comes bundled inside countless other applications that people use every day. More Information…

The SQLite file format is stable, cross-platform, and backwards compatible and the developers pledge to keep it that way through the year 2050. SQLite database files are commonly used as containers to transfer rich content between systems and as a long-term archival format for data. There are over 1 trillion (1e12) SQLite databases in active use.

SQLite source code is in the public-domain and is free to everyone to use for any purpose.

一、编译 SQLite

1.1 下载 SQLite 源码

打开 SQLite Download 页面,然后下载对应的压缩包文件。

图 1.1.1 SQLite Download

1.2 制作编译环境

首先,随便找个位置新建一个编译用的目录,这里新建一个 sqlite3 文件夹。

然后,将下载下来的压缩包文件全部解压,并将


  1. sqlite-amalgamation-xxx 文件夹中的 sqlite3.h;
  2. sqlite-dll-win-x64/x86-xxx 文件夹中的 sqlite3.defsqlite3.dll

全部复制到编译目录 sqlite3 中。

最后你得到的编译目录结构应该如下:

sqlite3
 |
 +---+ sqlite3.h
 +---+ sqlite3.def
 +---+ sqlite3.dll

1.3 编译 SQLite 源码

首先,打开 Developer Command Prompt for VS 2022 或者 Developer PowerShell for VS 2022,同时将环境设置为前面整理好的编译目录,即 sqlite3 文件夹。

然后,输入命令 lib /def:sqlite3.def(适用于 32 位) 或者 lib /def:sqlite3.def /machine:X64(适用于 64 位),并等待程序运行结束。这个过程一般很快,而且不会出什么问题。

图 1.3.1 编译 SQLite 源码

二、在 VS 中引入 SQLite

2.1 创建依赖库结构

首先,你需要将必要的文件添加到你的项目目录中,至于怎么添加全看个人习惯。

我习惯性会准备大致以下的结构到我的项目中(仅供参考):

sqlite3
 |
 + include
 |  |
 |  + sqlite3.h
 |
 + lib
    |
    + sqlite3.dll
    |
    + sqlite3.lib

一切准备完毕后,可以右键你的项目,打开“项目属性页”,并进行以下配置操作。

2.2 配置“附加库目录”

在“配置属性 - C/C++ - 常规”中的附加包含目录添加以下内容(仅供参考):

$(ProjectDir)sqlite3\include
注意

$(ProjectDir) 是指 VS 解决方案所在目录。

2.3 配置“附加库目录”

在“配置属性 - 链接器 - 常规”中的附加库目录添加以下内容(仅供参考):

$(ProjectDir)sqlite3\lib

2.4 配置“附加依赖项”

在“配置属性 - 链接器 - 输入”中的附加依赖项添加以下内容(仅供参考):

sqlite3.lib

2.5 复制 DLL 文件到运行环境目录

这个问题暂时未知或者我未找到更好的解决方案。

你需要将 sqlite3.dll 文件复制到你的项目运行目录中,以解决程序运行找不到 sqlite3.dll 文件的错误

三、测试项目

你可以使用以下代码进行测试你的项目是否成功引入了 SQLite3 库:

#include <iostream>
extern "C" {
    #include <sqlite3.h>
}

int main() {
    sqlite3* db;
    char* errMsg = nullptr;
    int exitCode;

    // 打开数据库(如果数据库不存在,将会创建一个)
    exitCode = sqlite3_open("test.db", &db);
    
    if (exitCode) {
        std::cerr << "Error opening SQLite database: " << sqlite3_errmsg(db) << std::endl;
        return exitCode;
    } else {
        std::cout << "Opened SQLite database successfully!" << std::endl;
    }

    // 创建一个表格
    const char* createTableSQL = "CREATE TABLE IF NOT EXISTS test_table("
                                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                                 "name TEXT NOT NULL);";
    
    exitCode = sqlite3_exec(db, createTableSQL, nullptr, nullptr, &errMsg);
    
    if (exitCode != SQLITE_OK) {
        std::cerr << "Error creating table: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    } else {
        std::cout << "Table created successfully!" << std::endl;
    }

    // 插入数据
    const char* insertDataSQL = "INSERT INTO test_table (name) VALUES ('test name');";
    
    exitCode = sqlite3_exec(db, insertDataSQL, nullptr, nullptr, &errMsg);
    
    if (exitCode != SQLITE_OK) {
        std::cerr << "Error inserting data: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    } else {
        std::cout << "Data inserted successfully!" << std::endl;
    }

    // 查询数据
    const char* selectSQL = "SELECT * FROM test_table;";
    sqlite3_stmt* stmt;

    exitCode = sqlite3_prepare_v2(db, selectSQL, -1, &stmt, nullptr);
    
    if (exitCode == SQLITE_OK) {
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            int id = sqlite3_column_int(stmt, 0);
            const unsigned char* name = sqlite3_column_text(stmt, 1);
            std::cout << "ID: " << id << ", Name: " << name << std::endl;
        }
    } else {
        std::cerr << "Error querying data: " << sqlite3_errmsg(db) << std::endl;
    }

    // 清理资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);

    return 0;
}

四、解决 SQLite3 中文乱码问题

4.1 乱码原因

之所以会出现乱码,是因为在 Windows 平台 VS 默认的编码是 GBK(通常是 GB2312),但是 SQLite3 使用的是 UTF-8 编码

而之所以英文字符及阿拉伯数字等可以被正常显示,唯独中文字符不行,这是因为 UTF-8 和 GBK 都兼容 ASCII 编码(也就是在 UTF-8 和 GBK 编码中都使用相同的 ASCII 编码表示数字和英文等字符)。

4.2 解决方案

目前我所掌握的解决方案就是通过 WINAPI 进行字符转码,而这需要唯一注意的是 SQLite3 使用 UTF-8 编码,VS 默认使用 GBK 编码,转码的时候别转错了方向即可。至于字母和数字等字符,如果理解了前面说的“乱码原因”,那想必也会有自己的答案吧!

#include <iostream>
#include <string>
#include <Windows.h>

// GBK 转 UTF-8
std::string GBKToUTF8(const std::string& gbkStr) {
    // 将 GBK 转换为宽字符(UTF-16)
    int wcharLen = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), static_cast<int>(gbkStr.length()), nullptr, 0);
    if (wcharLen <= 0) {
        return ""; // 转换失败
    }
    
    std::wstring wstr(wcharLen, 0);
    MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), static_cast<int>(gbkStr.length()), &wstr[0], wcharLen);

    // 将宽字符(UTF-16)转换为 UTF-8
    int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), static_cast<int>(wstr.length()), nullptr, 0, nullptr, nullptr);
    if (utf8Len <= 0) {
        return ""; // 转换失败
    }

    std::string utf8Str(utf8Len, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), static_cast<int>(wstr.length()), &utf8Str[0], utf8Len, nullptr, nullptr);

    return utf8Str;
}

// UTF-8 转 GBK
std::string UTF8ToGBK(const std::string& utf8Str) {
    // 将 UTF-8 转换为宽字符(UTF-16)
    int wcharLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), static_cast<int>(utf8Str.length()), nullptr, 0);
    if (wcharLen <= 0) {
        return ""; // 转换失败
    }
    
    std::wstring wstr(wcharLen, 0);
    MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), static_cast<int>(utf8Str.length()), &wstr[0], wcharLen);

    // 将宽字符(UTF-16)转换为 GBK
    int gbkLen = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(wstr.length()), nullptr, 0, nullptr, nullptr);
    if (gbkLen <= 0) {
        return ""; // 转换失败
    }

    std::string gbkStr(gbkLen, 0);
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(wstr.length()), &gbkStr[0], gbkLen, nullptr, nullptr);

    return gbkStr;
}

int main() {
    std::string gbkStr = "GBK编码的字符串";
    std::string utf8Str = GBKToUTF8(gbkStr);

    std::cout << "GBK to UTF-8: " << utf8Str << std::endl;

    std::string gbkStrBack = UTF8ToGBK(utf8Str);
    std::cout << "UTF-8 to GBK: " << gbkStrBack << std::endl;

    return 0;
}
补充

在研究这个问题的时候,我遇到了一点小问题,于是在 StackOverflow 上提出了相关的问题,感兴趣可以自行了解:[C++]String is corrupted after being transcoded


文章作者: SeaYJ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 SeaYJ !
评论
  目录