C/C++語言操作sqlite數據庫(增刪改查)


在某項目中,需要在前端相機中做人臉比對,因此需要在前端相機中增加一個人臉底庫,人臉底庫由uuid和人臉特征值組成。其中特征值為512個float數據,移植sqlite用來保存底庫信息,首先寫了一個demo,驗證可行性之后應用到實際項目中

    sqlite3 * db= NULL;
    int rc = 0;
    char * sql = new char[800];//這個要適當的申請大一點,要不然不夠用。
    char * zErrMsg = NULL;

    string id1 = "aaa";//用來模擬32位的uuid.
    std::vector<float> feature1{0.12, 0.23, 0.34, 0.45, 0.56, 0.67};//用來模擬512個人臉特征值.

    string id2 = "bbb";//用來模擬32位的uuid.
    std::vector<float> feature2{1.12, 1.23, 1.34, 1.45, 1.56, 1.67};//用來模擬512個人臉特征值.

    string id3 = "ccc";//用來模擬32位的uuid.
    std::vector<float> feature3{2.12, 2.23, 2.34, 2.45, 2.56, 2.67};//用來模擬512個人臉特征值.

    string id4 = "ddd";//用來模擬32位的uuid.
    std::vector<float> feature4{3.12, 3.23, 3.34, 3.45, 3.56, 3.67};//用來模擬512個人臉特征值.


    //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了
    cJSON *root1, *js_feature1;
    root1 = cJSON_CreateObject();
    cJSON_AddItemToObject(root1, "face_feature1", js_feature1 = cJSON_CreateArray());
    for(int i = 0; i < feature1.size(); i++)
    {
        cJSON_AddItemToArray(js_feature1, cJSON_CreateNumber(feature1.at(i)));    
    }    
    char *s1 = cJSON_PrintUnformatted(root1);    
    printf("s1:%s\n", s1);

    //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了
    cJSON *root2, *js_feature2;
    root2 = cJSON_CreateObject();
    cJSON_AddItemToObject(root2, "face_feature2", js_feature2 = cJSON_CreateArray());
    for(int i = 0; i < feature2.size(); i++)
    {
        cJSON_AddItemToArray(js_feature2, cJSON_CreateNumber(feature2.at(i)));    
    }    
    char *s2 = cJSON_PrintUnformatted(root2);    
    printf("s2:%s\n", s2);

    //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了
    cJSON *root3, *js_feature3;
    root3 = cJSON_CreateObject();
    cJSON_AddItemToObject(root3, "face_feature3", js_feature3 = cJSON_CreateArray());
    for(int i = 0; i < feature3.size(); i++)
    {
        cJSON_AddItemToArray(js_feature3, cJSON_CreateNumber(feature3.at(i)));    
    }    
    char *s3 = cJSON_PrintUnformatted(root3);    
    printf("s2:%s\n", s3);

    //先把人臉特征值的float數組轉成json,然后保存到數據庫中。cjson的源碼和例程在你自己的github上保存了
    cJSON *root4, *js_feature4;
    root4 = cJSON_CreateObject();
    cJSON_AddItemToObject(root4, "face_feature4", js_feature4 = cJSON_CreateArray());
    for(int i = 0; i < feature4.size(); i++)
    {
        cJSON_AddItemToArray(js_feature4, cJSON_CreateNumber(feature4.at(i)));    
    }    
    char *s4 = cJSON_PrintUnformatted(root4);    
    printf("s2:%s\n", s4);
      
    sqlite3_initialize();
    rc = sqlite3_open_v2("featureList.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);//這時候登錄嵌入式設備,你會看見創建了一個featureList.db的文件。
    if(rc != SQLITE_OK)
    {
        sqlite3_close_v2(db);
        printf("open featureList sql fail\n");
    }
    else
    {
        printf("open featureList sql success\n");
    }

    //這里的table名字featureList為前面open函數時的名字featureList,
    sprintf(sql, "CREATE TABLE featureList(ID INTEGER PRIMARY KEY AUTOINCREMENT, uuid VARCHAR(10),feature VARCHAR(10));"); 
    sqlite3_exec(db, sql, 0, 0, &zErrMsg);


    //插入數據
    //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來,
    sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id1.c_str(), s1);
    sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );

    //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來,
    sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id2.c_str(), s2);
    sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );

    //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來,
    sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id3.c_str(), s3);
    sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );

    //ID傳入NULL,那么會自動遞增,另外這里的%s要用單引號括起來,
    sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id4.c_str(), s4);
    sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );


    //查詢數據
    int nrow = 0, ncolumn = 0;
    char **azResult; 
    sprintf(sql, "SELECT * FROM featureList");
    sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
    printf("row:%d, column:%d\n", nrow, ncolumn);
    for(int i = 0; i < (nrow + 1)*ncolumn; i++)
    {
        /**********************************************************************************************
        注意這里無論是ID,還是uuid,還是feature都是用%s打印的,那么說明雖然我們定義的時候ID是定義成了整型,
        但是實際上里面保存的時候是按照字符類型保存的,經測試,如果用用%d打印那么打印出來的是49 50這種,也就是1,2的ASCII碼。
        ***********************************************************************************************/
        printf("azResult[%d] = %s\n", i, azResult[i]);
    }

    string deleteId = "3";//定義成string類型,不要定義成int類型,
    printf("deleteId:%s\n", deleteId.c_str());
    sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str());
    printf("delete sql is:%s\n", sql);
    rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    if(rc == SQLITE_OK)
    {
        //作用是重新構建數據庫文件,回收空白空間,減小數據庫文件的大小。
        printf("delete success\n");
    }
    else
    {    
        printf("delete fail!\n");
    }

    /**********************************************************************************
    如果本來的ID是1 2 3 4,我們把3刪除,那么ID變為1 2 4,UPDATE語句的作用是把ID重新排序成1 2 3.
    剛開始這里寫的是ID>1,這樣是錯誤的,應該是從刪除的元素開始ID=ID-1,刪除元素前面的ID是不用改的。
    sprintf(sql, "UPDATE featureList SET ID=ID-1 WHERE ID>1"); error
    ***********************************************************************************/
    sprintf(sql, "UPDATE featureList SET ID=ID-1 WHERE ID>%s", deleteId.c_str());
    rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);

    //刪除之后再次查詢看刪除是否正常
    sprintf(sql, "SELECT * FROM featureList");
    sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
    printf("row:%d, column:%d\n", nrow, ncolumn);
    for(int i = 0; i < (nrow + 1)*ncolumn; i++)
    {
        //注意這里是用%s打印的,雖然我們定義ID的時候是整型,但是實際上里面保存的時候是字符型的,
        printf("azResult[%d] = %s\n", i, azResult[i]);
    }

    //釋放空間
    delete[] sql;
    sqlite3_free_table(azResult);
    sqlite3_close(db);

打印的log如下圖:

 使用過程中遇到的問題:

>>用上面的語句創建的數據庫,uuid的類型是C++中string,而不是C語言中的char,

sprintf(sql, "CREATE TABLE featureList(ID INTEGER PRIMARY KEY AUTOINCREMENT, uuid VARCHAR(10),feature VARCHAR(10));"); 
    sLabel = to_string(label);
    for(int i = 1; i <= nrow; i++)
    {
        printf("sLabel.c_str():%s\n", sLabel.c_str());
        cout<<sLabel<<endl;
        printf("azResult[i*ncolumn + 1]:%s\n", azResult[i*ncolumn + 1]);

        printf("strlen(sLabel.c_str()):%d\n", strlen(sLabel.c_str()));
        printf("strlen(azResult[i*ncolumn + 1]):%d\n", strlen(azResult[i*ncolumn + 1]));

//if(sLabel.c_str() == azResult[i*ncolumn + 1]) //error if(sLabel == azResult[i*ncolumn + 1]) { deleteId = azResult[i*ncolumn]; printf("deleteId:%s\n", deleteId.c_str()); sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str()); printf("delete sql is:%s\n", sql); rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg); if(rc == SQLITE_OK) { printf("delete success\n"); } else { printf("delete fail!\n"); return -1; } } }

上面的代碼中,sLabel.c_str() 和 azResult[i*ncolumn + 1]用printf打印出來之后發現值是一樣的,但是下面的 if(sLabel.c_str() == azResult[i*ncolumn + 1])卻進不去,通過strlen發現兩者的長度不一樣,這是因為azResult[i*ncolumn + 1]是string類型,把if(sLabel.c_str() == azResult[i*ncolumn + 1])修改為if(sLabel == azResult[i*ncolumn + 1]),問題解決。

 >>數據庫中保存中文信息

labelname = "電腦";
sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s','%s');", sLabel.c_str(), s, labelname.c_str()); //sLabel要用c語言中的字符串形式,不能用C++中的string類型。

就直接把中文賦值就好了,不需要進行相應的編碼轉換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM