sqlite3数据库之blob数据类型读写

sqlite3数据库之blob数据类型读写

近期在开发过程中需要在数据库中保存二进制文件,于是去了解了一下sqlite3的数据类型,发现blob可以存储二进制数据。
但是blob要如何操作呢?用什么语句呢?
其实它是需要操作sqlite3库的一些底层API来实现。
下面我们就来做实验。
先上测试代码:

#include "Wdebug.h"

#include "sqlite/Wsqlite.h"
#include <stdlib.h>
#define     TABLE_NAME      "TEST_BLOB"
typedef struct {
    TUint16     len;
    void*       pdata;
} TBlobData;
void PrintList (TBlobData data)
{
    if (data.pdata) {
        TUint8* pvalue = (TUint8*)data.pdata;
        printf ("len(%d):", data.len);
        for (int i = 0; i < data.len; i++) {
            printf ("%d  ", pvalue[i]);
        }
        printf ("\n");
    } else {
        printf ("data is NULL!\n");
    }
}
int main (int argc, char* argv[])
{
    TBlobData data;
    struct TsqlCtrl* This = CreateSqlCtrl("database.db");
    if (This) {
        TsqlCtrlDelTable (This, TABLE_NAME);
        if (TsqlCtrlExec(This, "CREATE TABLE "TABLE_NAME" ("
        "id INTEGER PRIMARY KEY"
        ",NAME TEXT NOT NULL"
        ",age INTEGER"
        ",address TEXT"
        ",Data1 BLOB"
        ");"
        , NULL, NULL) != WSQLITE_TRUE) {
            Werr ("&#x521B;&#x5EFA;&#x8868;&#x5931;&#x8D25;&#xFF01;");
        }
        TsqlCtrlExec (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address) VALUES (NULL, '&#x5F20;&#x4E09;', 19, '&#x5317;&#x4EAC;')", NULL, NULL);
        TsqlCtrlExec (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address) VALUES (NULL, '&#x674E;&#x56DB;', 7, '&#x4E0A;&#x6D77;')" , NULL, NULL);
        TsqlCtrlExec (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address) VALUES (NULL, '&#x5218;&#x4E94;', 39, '&#x5E7F;&#x5DDE;')", NULL, NULL);
        TUint8 value[10];
        for (int i = 0; i < sizeof (value); i++) {
            value[i] = i + 1;
        }
        TsqlCtrlWriteBlob (This, "UPDATE "TABLE_NAME" SET Data1=? WHERE NAME='&#x5F20;&#x4E09;'", value, sizeof (value), 1);
        for (int i = 0; i < sizeof (value); i++) {
            value[i] = i + 5;
        }
        TsqlCtrlWriteBlob (This, "UPDATE "TABLE_NAME" SET Data1=? WHERE NAME='&#x674E;&#x56DB;'", value, sizeof (value) - 3, 1);
        for (int i = 0; i < sizeof (value); i++) {
            value[i] = i + 20;
        }
        TsqlCtrlWriteBlob (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address, Data1) VALUES (NULL, '&#x8001;&#x516D;', 24, '&#x6DF1;&#x5733;', ?)", value, sizeof (value), 1);
        data = TsqlCtrlReadBlob (This, "SELECT Data1 FROM "TABLE_NAME" WHERE NAME='&#x5F20;&#x4E09;'", 0, value, sizeof (value));
        PrintList (data);
        data = TsqlCtrlReadBlob (This, "SELECT Data1 FROM "TABLE_NAME" WHERE NAME='&#x674E;&#x56DB;'", 0, value, sizeof (value));
        PrintList (data);
        data = TsqlCtrlReadBlob (This, "SELECT id FROM "TABLE_NAME" WHERE NAME='&#x674E;&#x56DB;'", 0, value, sizeof (value));
        PrintList (data);
        data = TsqlCtrlReadBlob (This, "SELECT Data1 FROM "TABLE_NAME" WHERE NAME='&#x8001;&#x516D;'", 0, value, sizeof (value));
        PrintList (data);
        TsqlCtrlDestroy(This);
    }
}
</stdlib.h>

TsqlCtrl是我封装的一个结构体。
首先先创建一个带blob数据类型的表。然后再插入几条信息。通过UPDATE和INSERT语句修改和添加blob数据。blob数据部分用?代替。
底层实现代码如下:

sql::Ret sql::sqlite::WriteBlob (const char* const  sqlCmd, void* pdata, const TUint32 length, const TUint8 column_index)
{
    sql::Ret ret = sql::False;
    sqlite3_stmt* stmt = NULL;
    if (!pdata || length == 0) {
        return sql::False;
    }
    std::lock_guard<std::mutex> guard(this->mtx);
    if(sqlite3_prepare(this->db, sqlCmd, -1, &stmt, NULL)==SQLITE_OK) {
        sqlite3_bind_blob(stmt, column_index, pdata, length, NULL);
        if (sqlite3_step(stmt)==SQLITE_DONE) {
            ret = sql::True;
        }
        sqlite3_finalize(stmt);
    }
    return ret;
}

TBlobData sql::sqlite::ReadBlob (const char* const  sqlCmd, const TUint8 column_index, void* pdata, const TUint32 MaxSize)
{
    TBlobData Data;
    sqlite3_stmt* stmt = NULL;
    Data.len = 0;
    Data.pdata = nullptr;
    if (pdata&&MaxSize==0) {
        return Data;
    }
    std::lock_guard<std::mutex> guard(this->mtx);
    if(sqlite3_prepare(this->db, sqlCmd, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            const void* val = sqlite3_column_blob(stmt, column_index);
            Data.len  = sqlite3_column_bytes(stmt, column_index);
            if (pdata) {
                Data.pdata = pdata;
                if (Data.len > MaxSize) Data.len = MaxSize;
            } else {
                Data.pdata = malloc (Data.len);
            }
            if (Data.pdata) {
                memcpy (Data.pdata, val, Data.len);
            } else {
                Data.len = 0;
            }
        }
        sqlite3_finalize(stmt);
    }
    return Data;
}
</std::mutex></std::mutex>

1、写入过程
这是一条指令修改一个blob数据的代码,先用sqlite3_prepare函数解析sql语句获得sqlite3_stmt。
sqlite3_prepare
第一个参数为数据库句柄
第二个参数为sql语句
第三个参数为sql语句的最大字节长度
第四个参数为获取到的声明句柄sqlite3_stmt*
第五个参数为指向sql语句中未使用部分的指针
然后用sqlite3_bind_blob绑定blob数据到sqlite3_stmt
sqlite3_bind_blob
第一个参数为sqlite3_stmt句柄
第二个参数为?所在列号
第三个参数为需要写入的blob数据起始地址
第四个参数为写入长度
第五个参数类型为void()(void),暂时还不清楚,应该是回调函数指针,置为空即可。

第三步就是用sqlite3_step执行sqlite3_stmt句柄内容;执行完用sqlite3_finalize销毁句柄即可。
注意:
在写入时sqlite3_bind_blob的第二个参数为?所在的列号是从1开始数的,并非从0开始!具体可参考示例代码。

2、读取过程
也是先通过sqlite3_prepare函数解析sql语句获得句柄,然后通过sqlite3_step执行句柄内容获得查询结果。最后通过sqlite3_column_blob函数获得对应列的存储数据以及用sqlite3_column_bytes函数获得对应列的数据长度。最后用sqlite3_finalize释放句柄。
注意:
sqlite3_column_blob的第二个参数为列号,跟写入过程有所不同,这个是从0开始的,具体可参考测试代码。

以上测试代码的执行结果如下:

sqlite3数据库之blob数据类型读写
看第四行输出为len(1):50
由此可知
data = TsqlCtrlReadBlob (This, “SELECT id FROM “TABLE_NAME” WHERE NAME=’李四'”, 0, value, sizeof (value));
这一行查询的结果是id的值,50为字符2的ASCII码,而李四这条记录就是在第二行。
sqlite3数据库之blob数据类型读写
看TsqlCtrlWriteBlob (This, “UPDATE “TABLE_NAME” SET Data1=? WHERE NAME=’李四'”, value, sizeof (value) – 3, 1);和TsqlCtrlWriteBlob (This, “INSERT INTO “TABLE_NAME” (id, NAME, age, address, Data1) VALUES (NULL, ‘老六’, 24, ‘深圳’, ?)”, value, sizeof (value), 1);的执行结果,显然插入与更新的时候?的列号是不受其他字段影响的,只计算?是在所有?中的第几列,且是从1开始递增。

如一次读写多个blob数据,则在在sqlite3_step之前绑定多个数据或读出时读出多个数据即可。
以一次读写两个blob数据类型为例:

sql::Ret sql::sqlite::WriteBlob (const char* const  sqlCmd, TBlobData data)
{
    sql::Ret ret = sql::False;
    sqlite3_stmt* stmt = NULL;
    std::lock_guard<std::mutex> guard(this->mtx);
    if(sqlite3_prepare(this->db, sqlCmd, -1, &stmt, NULL)==SQLITE_OK) {
        // &#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;data.GetData(i)->index&#x4EE3;&#x8868;sql&#x8BED;&#x53E5;&#x4E2D;?&#x7684;&#x4F4D;&#x7F6E;&#xFF08;&#x76F8;&#x5BF9;&#x4E8E;VALUES&#x4E2D;&#x7684;&#x4F4D;&#x7F6E;&#x4ECE;0&#x5F00;&#x59CB;&#xFF0C;&#x5982;&#xFF1A;VALUES(1, ?)&#xFF0C;&#x5219;&#x95EE;&#x53F7;&#x7684;&#x4F4D;&#x7F6E;&#x4E3A;1&#xFF09;
        sqlite3_bind_blob(stmt, data.column[0], data.pdata[0], data.len[0], NULL);
        sqlite3_bind_blob(stmt, data.column[1], data.pdata[1], data.len[1], NULL);
        if (sqlite3_step(stmt)==SQLITE_DONE) {
            ret = sql::True;
        }
        sqlite3_finalize(stmt);
    }
    return ret;
}

TBlobData sql::sqlite::ReadBlob (const char* const  sqlCmd, TBlobData data)
{
    TBlobData errdata;
    sqlite3_stmt* stmt = NULL;
    std::lock_guard<std::mutex> guard(this->mtx);
    if(sqlite3_prepare(this->db, sqlCmd, -1, &stmt, NULL) == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            TUint32 slen;
            const void* val;
            val = sqlite3_column_blob(stmt, data.column[0]);
            slen  = sqlite3_column_bytes(stmt,  data.column[0]);
            if (data.len[0] > slen) data.len[0] = slen;
            memcpy (data.pdata[0], val, data.len[0]);
            val = sqlite3_column_blob(stmt, data.column[1]);
            slen  = sqlite3_column_bytes(stmt,  data.column[1]);
            if (data.len[1] > slen) data.len[1] = slen;
            memcpy (data.pdata[1], val, data.len[1]);
        } else {
            sqlite3_finalize(stmt);
            return errdata;
        }
        sqlite3_finalize(stmt);
    } else {
        return errdata;
    }
    return data;
}
</std::mutex></std::mutex>
void main(int argc, char* argv[])
{
    TBlobData data;
    TBlobData data2;
    struct TsqlCtrl* This = CreateSqlCtrl("database.db");
    if (This) {
        TsqlCtrlDelTable (This, TABLE_NAME);
        if (TsqlCtrlExec(This, "CREATE TABLE "TABLE_NAME" ("
        "id INTEGER PRIMARY KEY"
        ",NAME TEXT NOT NULL"
        ",age INTEGER"
        ",address TEXT"
        ",Data1 BLOB"
        ",Data2 BLOB"
        ");"
        , NULL, NULL) != WSQLITE_TRUE) {
            Werr ("&#x521B;&#x5EFA;&#x8868;&#x5931;&#x8D25;&#xFF01;");
        }
        TsqlCtrlExec (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address) VALUES (NULL, '&#x5F20;&#x4E09;', 19, '&#x5317;&#x4EAC;')", NULL, NULL);
        TsqlCtrlExec (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address) VALUES (NULL, '&#x674E;&#x56DB;', 7, '&#x4E0A;&#x6D77;')" , NULL, NULL);
        TsqlCtrlExec (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address) VALUES (NULL, '&#x5218;&#x4E94;', 39, '&#x5E7F;&#x5DDE;')", NULL, NULL);
        TUint8 value[10];
        TUint8 value2[10];
        data2.len[0] = sizeof (value);
        data2.len[1] = sizeof (value2);
        data2.column[0] = 1;
        data2.column[1] = 2;
        data2.pdata[0] = value;
        data2.pdata[1] = value2;
        for (int i = 0; i < sizeof (value); i++) {
            value[i] = i + 1;
            value2[i] = i + 3;
        }
        TsqlCtrlWriteBlob (This, "UPDATE "TABLE_NAME" SET Data1=?,Data2=? WHERE NAME='&#x5F20;&#x4E09;'", data2);
        for (int i = 0; i < sizeof (value); i++) {
            value[i] = i + 5;
            value2[i] = i + 9;
        }
        TsqlCtrlWriteBlob (This, "UPDATE "TABLE_NAME" SET Data1=?,Data2=? WHERE NAME='&#x674E;&#x56DB;'", data2);
        for (int i = 0; i < sizeof (value); i++) {
            value[i] = i + 20;
            value2[i] = i + 23;
        }
        TsqlCtrlWriteBlob (This, "INSERT INTO "TABLE_NAME" (id, NAME, age, address, Data1, Data2) VALUES (NULL, '&#x8001;&#x516D;', 24, '&#x6DF1;&#x5733;', ?, ?)", data2);
        data2.column[0] = 0;
        data2.column[1] = 1;
        data = TsqlCtrlReadBlob (This, "SELECT Data1,Data2 FROM "TABLE_NAME" WHERE NAME='&#x5F20;&#x4E09;'", data2);
        PrintList (data);
        data = TsqlCtrlReadBlob (This, "SELECT Data1,Data2 FROM "TABLE_NAME" WHERE NAME='&#x674E;&#x56DB;'", data2);
        PrintList (data);
        data = TsqlCtrlReadBlob (This, "SELECT id,Data1 FROM "TABLE_NAME" WHERE NAME='&#x674E;&#x56DB;'", data2);
        PrintList (data);
        data = TsqlCtrlReadBlob (This, "SELECT Data1,Data2 FROM "TABLE_NAME" WHERE NAME='&#x8001;&#x516D;'", data2);
        PrintList (data);
        TsqlCtrlDestroy(This);
    }
}

以下为执行结果:

sqlite3数据库之blob数据类型读写
呀!不知不觉已经过了十点半了。。。粗略写写,后面完善了代码,我再上传我的数据库操作接口吧。得赶紧回家洗澡睡觉了。。。

完善的完整代码已上传:源代码下载入口
类使用说明及测试案例
基础篇

各API的使用说明将在后续陆陆续续发表博客进行帮助说明,源代码附带的注释也很详尽,通过注释也可轻松理解代码及框架思路等

Original: https://blog.csdn.net/Programmer_Dong/article/details/115678387
Author: pioneer_t
Title: sqlite3数据库之blob数据类型读写

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/816677/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球