<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # SQLite C 教程 > 原文: [http://zetcode.com/db/sqlitec/](http://zetcode.com/db/sqlitec/) 這是 SQLite 數據庫的 C 編程教程。 它涵蓋了使用 C 語言進行 SQLite 編程的基礎。 您可能還想查看 ZetCode 上的 [SQLite 教程](/db/sqlite/), [MySQL C 教程](/db/mysqlc/)或 [PostgreSQL C 教程](/db/postgresqlc/)。 ## SQLite 數據庫 _SQLite_ 是嵌入式關系數據庫引擎。 它的開發者稱其為自包含,無服務器,零配置和事務型 SQL 數據庫引擎。 它目前非常流行,當今全球使用著數億冊。 SQLite 在 Solaris 10,Mac OS,Android 或 iPhone 中使用。 Qt4 庫內置了對 SQLite 以及 Python 和 PHP 的支持。 許多流行的應用內部都使用 SQLite,例如 Firefox,Google Chrome 或 Amarok。 ## sqlite3 工具 _sqlite3_ 工具是 SQLite 庫的基于終端的前端。 它以交互方式求值查詢,并以多種格式顯示結果。 它也可以在腳本中使用。 它具有自己的元命令集,包括`.tables`,`.load`,`.databases`或`.dump`。 要獲取所有指令的列表,我們鍵入`.help`命令。 現在,我們將使用`sqlite3`工具創建一個新數據庫。 ```c $ sqlite3 test.db SQLite version 3.8.2 2013-12-06 14:53:30 Enter ".help" for instructions Enter SQL statements terminated with a ";" ``` 我們為`sqlite3 tool`提供了一個參數; `test.db`是數據庫名稱。 這是我們磁盤上的文件。 如果存在,則將其打開。 如果不是,則創建它。 ```c sqlite> .tables sqlite> .exit $ ls test.db ``` `.tables`命令提供`test.db`數據庫中的表的列表。 當前沒有表。 `.exit`命令終止`sqlite3`命令行工具的交互式會話。 `ls` Unix 命令顯示當前工作目錄的內容。 我們可以看到`test.db`文件。 所有數據將存儲在該單個文件中。 ## C99 本教程使用 C99。 對于 GNU C 編譯器,我們需要使用`-std=c99`選項。 對于 Windows 用戶,強烈建議使用 Pelles C IDE。 (MSVC 不支持 C99。) ```c int rc = sqlite3_open("test.db", &db); ``` 在 C99 中,我們可以將聲明與代碼混合使用。 在較早的 C 程序中,我們需要將這一行分成兩行。 ## SQLite 版本 在第一個代碼示例中,我們將獲得 SQLite 數據庫的版本。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { printf("%s\n", sqlite3_libversion()); return 0; } ``` `sqlite3_libversion()`函數返回指示 SQLite 庫的字符串。 ```c #include <sqlite3.h> ``` 該頭文件定義了 SQLite 庫提供給客戶端程序的接口。 它包含定義,函數原型和注釋。 它是 SQLite API 的權威來源。 ```c $ gcc -o version version.c -lsqlite3 -std=c99 ``` 我們使用 GNU C 編譯器編譯程序。 ```c $ ./version 3.8.2 ``` 這是示例的輸出。 在第二個示例中,我們再次獲得 SQLite 數據庫的版本。 這次我們將使用 SQL 查詢。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; sqlite3_stmt *res; int rc = sqlite3_open(":memory:", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION()", -1, &res, 0); if (rc != SQLITE_OK) { fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } rc = sqlite3_step(res); if (rc == SQLITE_ROW) { printf("%s\n", sqlite3_column_text(res, 0)); } sqlite3_finalize(res); sqlite3_close(db); return 0; } ``` `SQLITE_VERSION()`查詢用于獲取 SQLite 庫的版本。 ```c sqlite3 *db; ``` `sqlite3`結構定義數據庫句柄。 每個打開的 SQLite 數據庫均由數據庫句柄表示。 ```c sqlite3_stmt *res; ``` `sqlite3_stmt`結構表示單個 SQL 語句。 ```c int rc = sqlite3_open(":memory:", &db); ``` `sqlite3_open()`函數打開一個新的數據庫連接。 它的參數是數據庫名稱和數據庫句柄。 `:memory:`是一個特殊的數據庫名稱,使用它可以打開內存數據庫。 該函數的返回代碼指示數據庫是否已成功打開。 成功建立連接后,將返回`SQLITE_OK`。 ```c if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } ``` 如果返回代碼指示錯誤,我們將消息打印到控制臺,關閉數據庫句柄,然后終止程序。 `sqlite3_errmsg()`函數返回錯誤的描述。 無論打開時是否發生錯誤,都應通過將其傳遞給`sqlite3_close()`函數來釋放與數據庫連接句柄關聯的資源。 ```c rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION()", -1, &res, 0); ``` 在執行 SQL 語句之前,必須先使用`sqlite3_prepare*`函數之一將其編譯為字節碼。 (不推薦使用`sqlite3_prepare()`函數。) `sqlite3_prepare_v2()`函數具有五個參數。 第一個參數是從`sqlite3_open()`函數獲得的數據庫句柄。 第二個參數是要編譯的 SQL 語句。 第三個參數是 SQL 語句的最大長度,以字節為單位。 傳遞 -1 將導致 SQL 字符串被讀取到第一個零終止符,即第一個零終止符。 根據文檔,通過傳遞所提供的 SQL 字符串的確切字節數,可以獲得一些小的性能優勢。 第四個參數是語句句柄。 如果`sqlite3_prepare_v2()`成功運行,它將指向預編譯的語句。 最后一個參數是指向 SQL 語句未使用部分的指針。 只編譯 SQL 字符串的第一條語句,因此該參數指向未編譯的內容。 我們傳遞 0,因為參數對我們而言并不重要。 成功時,`sqlite3_prepare_v2()`返回`SQLITE_OK`; 否則返回錯誤代碼。 ```c if (rc != SQLITE_OK) { fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } ``` 這是`sqlite3_prepare_v2()`函數調用的錯誤處理代碼。 ```c rc = sqlite3_step(res); ``` `sqlite3_step()`運行 SQL 語句。 `SQLITE_ROW`返回碼表示還有另一行準備就緒。 我們的 SQL 語句僅返回一行數據,因此,我們只調用一次此函數。 ```c sqlite3_finalize(res); ``` `sqlite3_finalize()`函數破壞預備語句對象。 ```c sqlite3_close(db); ``` `sqlite3_close()`函數關閉數據庫連接。 ## 插入數據 我們創建一個`Cars`表并在其中插入幾行。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "DROP TABLE IF EXISTS Cars;" "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);" "INSERT INTO Cars VALUES(1, 'Audi', 52642);" "INSERT INTO Cars VALUES(2, 'Mercedes', 57127);" "INSERT INTO Cars VALUES(3, 'Skoda', 9000);" "INSERT INTO Cars VALUES(4, 'Volvo', 29000);" "INSERT INTO Cars VALUES(5, 'Bentley', 350000);" "INSERT INTO Cars VALUES(6, 'Citroen', 21000);" "INSERT INTO Cars VALUES(7, 'Hummer', 41400);" "INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; } ``` 我們連接到`test.db`數據庫,創建`Cars`表,然后在創建的表中插入 8 行。 ```c char *err_msg = 0; ``` 如果發生錯誤,該指針將指向創建的錯誤消息。 ```c int rc = sqlite3_open("test.db", &db); ``` 與`test.db`數據庫的連接已創建。 ```c char *sql = "DROP TABLE IF EXISTS Cars;" "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);" "INSERT INTO Cars VALUES(1, 'Audi', 52642);" "INSERT INTO Cars VALUES(2, 'Mercedes', 57127);" "INSERT INTO Cars VALUES(3, 'Skoda', 9000);" "INSERT INTO Cars VALUES(4, 'Volvo', 29000);" "INSERT INTO Cars VALUES(5, 'Bentley', 350000);" "INSERT INTO Cars VALUES(6, 'Citroen', 21000);" "INSERT INTO Cars VALUES(7, 'Hummer', 41400);" "INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);"; ``` 這些 SQL 語句創建一個`Cars`表并用數據填充它。 語句必須用分號分隔。 ```c rc = sqlite3_exec(db, sql, 0, 0, &err_msg); ``` `sqlite3_exec()`函數是`sqlite3_prepare_v2()`,`sqlite3_step()`和`sqlite3_finalize()`的便利包裝,它允許應用運行多個 SQL 語句而無需使用大量 C 代碼。 該函數的第三個參數是為從求值的 SQL 語句中出來的每個結果行調用的回調函數。 第四個參數是回調函數的第一個參數。 如果不需要它們,可以將 0 傳遞給這些參數。 如果發生錯誤,則最后一個參數指向分配的錯誤消息。 ```c sqlite3_free(err_msg); ``` 必須使用`sqlite3_free()`函數調用釋放分配的消息字符串。 ```c sqlite> .mode column sqlite> .headers on ``` 我們使用`sqlite3`工具驗證寫入的數據。 首先,我們修改數據在控制臺中的顯示方式。 我們使用列模式并打開標題。 ```c sqlite> SELECT * FROM Cars; Id Name Price ---------- ---------- ---------- 1 Audi 52642 2 Mercedes 57127 3 Skoda 9000 4 Volvo 29000 5 Bentley 350000 6 Citroen 21000 7 Hummer 41400 8 Volkswagen 21600 ``` 這是我們已寫入`Cars`表的數據。 ## 最后插入的行 ID 有時,我們需要確定最后插入的行的 ID。 為此,我們具有`sqlite3_last_insert_rowid()`函數。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open(":memory:", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT);" "INSERT INTO Friends(Name) VALUES ('Tom');" "INSERT INTO Friends(Name) VALUES ('Rebecca');" "INSERT INTO Friends(Name) VALUES ('Jim');" "INSERT INTO Friends(Name) VALUES ('Roger');" "INSERT INTO Friends(Name) VALUES ('Robert');"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "Failed to create table\n"); fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); } else { fprintf(stdout, "Table Friends created successfully\n"); } int last_id = sqlite3_last_insert_rowid(db); printf("The last Id of the inserted row is %d\n", last_id); sqlite3_close(db); return 0; } ``` 在內存中創建一個`Friends`表。 其`Id`列會自動增加。 ```c char *sql = "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT);" "INSERT INTO Friends(Name) VALUES ('Tom');" "INSERT INTO Friends(Name) VALUES ('Rebecca');" "INSERT INTO Friends(Name) VALUES ('Jim');" "INSERT INTO Friends(Name) VALUES ('Roger');" "INSERT INTO Friends(Name) VALUES ('Robert');"; ``` 在 SQLite 中,`INTEGER PRIMARY KEY`列自動增加。 還有一個`AUTOINCREMENT`關鍵字。 當在`INTEGER PRIMARY KEY AUTOINCREMENT`中應用時,會使用稍微不同的 ID 創建算法。 使用自動遞增的列時,除了自動遞增的列(省略了該列)外,我們需要明確聲明列名。 ```c int last_id = sqlite3_last_insert_rowid(db); printf("The last Id of the inserted row is %d\n", last_id); ``` `sqlite3_last_insert_rowid()`返回表中最近一次成功插入的行 ID。 ```c $ ./last_row_id Table Friends created successfully The last Id of the inserted row is 5 ``` 我們看到了程序的輸出。 ## 檢索數據 我們已經將一些數據插入`test.db`數據庫。 在下面的示例中,我們從數據庫中檢索數據。 ```c #include <sqlite3.h> #include <stdio.h> int callback(void *, int, char **, char **); int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "SELECT * FROM Cars"; rc = sqlite3_exec(db, sql, callback, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "Failed to select data\n"); fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; } int callback(void *NotUsed, int argc, char **argv, char **azColName) { NotUsed = 0; for (int i = 0; i < argc; i++) { printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; } ``` 我們使用`SELECT * FROM Cars` SQL 語句從`Cars`表中檢索所有行。 ```c int callback(void *, int, char **, char **); ``` 這是與`sqlite3_exec()`函數結合使用的回調函數的函數原型。 ```c int rc = sqlite3_open("test.db", &db); ``` 我們連接到`test.db`數據庫。 ```c char *sql = "SELECT * FROM Cars"; ``` 在這里,我們定義 SQL 語句以從`Cars`表中選擇所有數據。 ```c rc = sqlite3_exec(db, sql, callback, 0, &err_msg); ``` `sqlite3_exec()`函數對 SQL 語句進行賦值。 對于從求值的 SQL 語句出來的每個結果行,都會調用其回調函數。 ```c int callback(void *NotUsed, int argc, char **argv, char **azColName) { NotUsed = 0; for (int i = 0; i < argc; i++) { printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; } ``` 回調函數的第一個參數是`sqlite3_exec()`的第 4 個參數中提供的數據; 它通常不被使用。 第二個參數是結果中的列數。 第三個參數是表示行中字段的字符串數組。 最后一個參數是代表列名的字符串數組。 在函數主體中,我們遍歷所有列并打印其名稱和內容。 ```c $ ./select_all Id = 1 Name = Audi Price = 52642 Id = 2 Name = Mercedes Price = 57127 Id = 3 Name = Skoda Price = 9000 ... ``` 這是示例的部分輸出。 ## 參數化查詢 現在我們將提到參數化查詢。 參數化查詢(也稱為預準備語句)可提高安全性和性能。 當使用參數化查詢時,我們使用占位符,而不是直接將值寫入語句。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; char *err_msg = 0; sqlite3_stmt *res; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "SELECT Id, Name FROM Cars WHERE Id = ?"; rc = sqlite3_prepare_v2(db, sql, -1, &res, 0); if (rc == SQLITE_OK) { sqlite3_bind_int(res, 1, 3); } else { fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db)); } int step = sqlite3_step(res); if (step == SQLITE_ROW) { printf("%s: ", sqlite3_column_text(res, 0)); printf("%s\n", sqlite3_column_text(res, 1)); } sqlite3_finalize(res); sqlite3_close(db); return 0; } ``` 在該示例中,問號(?)用作占位符,稍后將其替換為實際值。 ```c char *sql = "SELECT Id, Name FROM Cars WHERE Id = ?"; ``` 問號用于為 SQL 查詢提供 ID。 ```c rc = sqlite3_prepare_v2(db, sql, -1, &res, 0); ``` `sqlite3_prepare_v2()`函數編譯 SQL 查詢。 ```c sqlite3_bind_int(res, 1, 3); ``` `sqlite3_bind_int()`將整數值綁定到預備語句。 占位符將替換為整數 3。該函數的第二個參數是要設置的 SQL 參數的索引,第三個參數是要綁定到該參數的值。 ```c int step = sqlite3_step(res); ``` `sqlite3_step()`函數求值 SQL 語句。 ```c if (step == SQLITE_ROW) { printf("%s: ", sqlite3_column_text(res, 0)); printf("%s\n", sqlite3_column_text(res, 1)); } ``` 如果有可用的數據行,則可以使用`sqlite3_column_text()`函數獲得兩列的值。 ```c $ ./parameterized 3: Skoda ``` 該示例返回 ID 和汽車的名稱。 第二個示例使用帶有命名占位符的參數化語句。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; char *err_msg = 0; sqlite3_stmt *res; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "SELECT Id, Name FROM Cars WHERE Id = @id"; rc = sqlite3_prepare_v2(db, sql, -1, &res, 0); if (rc == SQLITE_OK) { int idx = sqlite3_bind_parameter_index(res, "@id"); int value = 4; sqlite3_bind_int(res, idx, value); } else { fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db)); } int step = sqlite3_step(res); if (step == SQLITE_ROW) { printf("%s: ", sqlite3_column_text(res, 0)); printf("%s\n", sqlite3_column_text(res, 1)); } sqlite3_finalize(res); sqlite3_close(db); return 0; } ``` 我們使用命名的占位符選擇汽車的名稱和價格。 ```c char *sql = "SELECT Id, Name FROM Cars WHERE Id = @id"; ``` 命名的占位符以冒號(:)或符號(@)字符為前綴。 ```c int idx = sqlite3_bind_parameter_index(res, "@id"); ``` `sqlite3_bind_parameter_index()`函數返回給定名稱的 SQL 參數的索引。 ## 插入圖像 在本節中,我們將圖像插入到 SQLite 數據庫中。 請注意,有些人反對將圖像放入數據庫。 在這里,我們只展示如何做。 我們不討論是否將圖像保存在數據庫中的技術問題。 ```c sqlite> CREATE TABLE Images(Id INTEGER PRIMARY KEY, Data BLOB); ``` 對于此示例,我們創建一個名為`Images`的新表。 對于圖像,我們使用`BLOB`數據類型,表示二進制大型對象。 ```c #include <sqlite3.h> #include <stdio.h> int main(int argc, char **argv) { FILE *fp = fopen("woman.jpg", "rb"); if (fp == NULL) { fprintf(stderr, "Cannot open image file\n"); return 1; } fseek(fp, 0, SEEK_END); if (ferror(fp)) { fprintf(stderr, "fseek() failed\n"); int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } return 1; } int flen = ftell(fp); if (flen == -1) { perror("error occurred"); int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } return 1; } fseek(fp, 0, SEEK_SET); if (ferror(fp)) { fprintf(stderr, "fseek() failed\n"); int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } return 1; } char data[flen+1]; int size = fread(data, 1, flen, fp); if (ferror(fp)) { fprintf(stderr, "fread() failed\n"); int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } return 1; } int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } sqlite3_stmt *pStmt; char *sql = "INSERT INTO Images(Data) VALUES(?)"; rc = sqlite3_prepare(db, sql, -1, &pStmt, 0); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot prepare statement: %s\n", sqlite3_errmsg(db)); return 1; } sqlite3_bind_blob(pStmt, 1, data, size, SQLITE_STATIC); rc = sqlite3_step(pStmt); if (rc != SQLITE_DONE) { printf("execution failed: %s", sqlite3_errmsg(db)); } sqlite3_finalize(pStmt); sqlite3_close(db); return 0; } ``` 在此程序中,我們從當前工作目錄中讀取圖像,并將其寫入 SQLite `test.db`數據庫的`Images`表中。 ```c FILE *fp = fopen("woman.jpg", "rb"); if (fp == NULL) { fprintf(stderr, "Cannot open image file\n"); return 1; } ``` 我們從文件系統讀取二進制數據。 我們有一個名為`woman.jpg`的 JPG 圖像。 `fopen()`函數打開指定的文件以供讀取。 如果操作失敗,它將返回一個指向`FILE`對象的指針或`NULL`。 ```c fseek(fp, 0, SEEK_END); if (ferror(fp)) { fprintf(stderr, "fseek() failed\n"); int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } return 1; } ``` 我們使用`fseek()`函數將文件指針移到文件末尾。 我們需要確定圖像的大小。 如果發生錯誤,則設置錯誤指示器。 我們使用`fseek()`函數檢查指示器。 如果發生錯誤,將關閉打開的文件處理器。 ```c int flen = ftell(fp); if (flen == -1) { perror("error occurred"); int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } return 1; } ``` 對于二進制流,`ftell()`函數返回文件開頭的字節數,例如圖像文件的大小。 發生錯誤時,函數將返回 -1 并設置`errno`。 `perror()`函數將`errno`的值解釋為錯誤消息,并將其打印到標準錯誤輸出流。 ```c char data[flen+1]; ``` 該數組將存儲圖像數據。 ```c int size = fread(data, 1, flen, fp); ``` `fread()`函數從文件指針讀取數據并將其存儲在數據數組中。 該函數返回成功讀取的元素數。 ```c int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } ``` 讀取數據后,我們可以關閉文件處理器。 ```c char *sql = "INSERT INTO Images(Data) VALUES(?)"; ``` 該 SQL 語句用于將映像插入數據庫。 ```c rc = sqlite3_prepare(db, sql, -1, &pStmt, 0); ``` SQL 語句已編譯。 ```c sqlite3_bind_blob(pStmt, 1, data, size, SQLITE_STATIC); ``` `sqlite3_bind_blob()`函數將二進制數據綁定到已編譯的語句。 `SQLITE_STATIC`參數表示指向內容信息的指針是靜態的,不需要釋放。 ```c rc = sqlite3_step(pStmt); ``` 執行該語句,并將圖像寫入表中。 ## 讀取圖像 在本節中,我們將執行相反的操作。 我們將從數據庫表中讀取圖像。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { FILE *fp = fopen("woman2.jpg", "wb"); if (fp == NULL) { fprintf(stderr, "Cannot open image file\n"); return 1; } sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "SELECT Data FROM Images WHERE Id = 1"; sqlite3_stmt *pStmt; rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, 0); if (rc != SQLITE_OK ) { fprintf(stderr, "Failed to prepare statement\n"); fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } rc = sqlite3_step(pStmt); int bytes = 0; if (rc == SQLITE_ROW) { bytes = sqlite3_column_bytes(pStmt, 0); } fwrite(sqlite3_column_blob(pStmt, 0), bytes, 1, fp); if (ferror(fp)) { fprintf(stderr, "fwrite() failed\n"); return 1; } int r = fclose(fp); if (r == EOF) { fprintf(stderr, "Cannot close file handler\n"); } rc = sqlite3_finalize(pStmt); sqlite3_close(db); return 0; } ``` 我們從`Images`表中讀取圖像數據,并將其寫入另一個文件`woman2.jpg`中。 ```c FILE *fp = fopen("woman2.jpg", "wb"); if (fp == NULL) { fprintf(stderr, "Cannot open image file\n"); return 1; } ``` 我們以寫入模式打開一個二進制文件。 來自數據庫的數據被寫入文件。 ```c char *sql = "SELECT Data FROM Images WHERE Id = 1"; ``` 該 SQL 語句從`Images`表中選擇數據。 我們從第一行獲取二進制數據。 ```c if (rc == SQLITE_ROW) { bytes = sqlite3_column_bytes(pStmt, 0); } ``` `sqlite3_column_bytes()`函數返回`BLOB`中的字節數。 ```c fwrite(sqlite3_column_blob(pStmt, 0), bytes, 1, fp); ``` 使用`fwrite()`函數將二進制數據寫入文件。 `sqlite3_column_blob()`函數返回指向所選二進制數據的指針。 ```c if (ferror(fp)) { fprintf(stderr, "fwrite() failed\n"); return 1; } ``` `ferror()`函數檢查與流相關的錯誤指示符是否已設置。 ## 元數據 元數據是有關數據庫中數據的信息。 SQLite 中的元數據包含有關表和列的信息,我們在其中存儲數據。 受 SQL 語句影響的行數是元數據。 結果集中返回的行數和列數也屬于元數據。 可以使用`PRAGMA`命令獲取 SQLite 中的元數據。 SQLite 對象可能具有屬性,即元數據。 最后,我們還可以通過查詢 SQLite 系統`sqlite_master`表來獲取特定的元數據。 ```c #include <sqlite3.h> #include <stdio.h> int callback(void *, int, char **, char **); int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "PRAGMA table_info(Cars)"; rc = sqlite3_exec(db, sql, callback, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "Failed to select data\n"); fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; } int callback(void *NotUsed, int argc, char **argv, char **azColName) { NotUsed = 0; for (int i = 0; i < argc; i++) { printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; } ``` 在此示例中,我們發出`PRAGMA table_info(tableName)`命令,以獲取有關`Cars`表的一些元數據信息。 ```c char *sql = "PRAGMA table_info(Cars)"; ``` `PRAGMA table_info(tableName)`命令為`Cars`表中的每一列返回一行。 結果集中的列包括列順序號,列名稱,數據類型,該列是否可以為`NULL`以及該列的默認值。 ```c $ ./column_names cid = 0 name = Id type = INT notnull = 0 dflt_value = NULL pk = 0 ... ``` 這是示例的輸出。 在與元數據有關的下一個示例中,我們將列出`test.db`數據庫中的所有表。 ```c #include <sqlite3.h> #include <stdio.h> int callback(void *, int, char **, char **); int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "SELECT name FROM sqlite_master WHERE type='table'"; rc = sqlite3_exec(db, sql, callback, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "Failed to select data\n"); fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; } int callback(void *NotUsed, int argc, char **argv, char **azColName) { NotUsed = 0; for (int i = 0; i < argc; i++) { printf("%s\n", argv[i] ? argv[i] : "NULL"); } return 0; } ``` 該代碼示例將當前數據庫中的所有可用表打印到終端。 ```c char *sql = "SELECT name FROM sqlite_master WHERE type='table'"; ``` 表名存儲在系統`sqlite_master`表中。 ```c $ ./list_tables Cars Images ``` 這是一個示例輸出。 ## 事務 事務是針對一個或多個數據庫中數據的數據庫操作的基本單位。 事務中所有 SQL 語句的影響可以全部提交給數據庫,也可以全部回滾。 在 SQLite 中,除`SELECT`以外的任何命令都將啟動隱式事務。 同樣,在事務中,諸如`CREATE TABLE` ...,`VACUUM`和`PRAGMA`之類的命令將在執行之前提交先前的更改。 手動事務以`BEGIN TRANSACTION`語句開始,并以`COMMIT`或`ROLLBACK`語句結束。 SQLite 支持三種非標準事務級別:`DEFERRED`,`IMMEDIATE`和`EXCLUSIVE`。 ### 自動提交 默認情況下,SQLite 版本 3 在自動提交模式下運行。 在自動提交模式下,對數據庫的所有更改將在與當前數據庫連接關聯的所有操作完成后立即提交。 自動提交模式由`BEGIN`語句禁用,并由`COMMIT`或`ROLLBACK`重新啟用。 ```c #include <sqlite3.h> #include <stdio.h> int main() { sqlite3 *db; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } printf("Autocommit: %d\n", sqlite3_get_autocommit(db)); sqlite3_close(db); return 0; } ``` 本示例檢查數據庫是否處于自動提交模式。 ```c printf("Autocommit: %d\n", sqlite3_get_autocommit(db)); ``` 如果數據庫未處于自動提交模式,則`sqlite3_get_autocommit()`函數返回零。 如果處于自動提交模式,它將返回非零值。 ```c $ ./get_ac_mode Autocommit: 1 ``` 該示例確認默認情況下 SQLite 處于自動提交模式。 下一個示例進一步闡明了自動提交模式。 在自動提交模式下,每個非`SELECT`語句都是一個立即提交的小事務。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "DROP TABLE IF EXISTS Friends;" "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT);" "INSERT INTO Friends(Name) VALUES ('Tom');" "INSERT INTO Friends(Name) VALUES ('Rebecca');" "INSERT INTO Friends(Name) VALUES ('Jim');" "INSERT INTO Friend(Name) VALUES ('Robert');"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; } ``` 我們創建`Friends`表,并嘗試用數據填充它。 ```c char *sql = "DROP TABLE IF EXISTS Friends;" "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT);" "INSERT INTO Friends(Name) VALUES ('Tom');" "INSERT INTO Friends(Name) VALUES ('Rebecca');" "INSERT INTO Friends(Name) VALUES ('Jim');" "INSERT INTO Friend(Name) VALUES ('Robert');"; ``` 最后一條 SQL 語句有一個錯誤; 沒有朋友表。 ```c $ ./autocommit SQL error: no such table: Friend $ sqlite3 test.db sqlite> .tables Cars Friends Images sqlite> SELECT * FROM Friends; 1|Tom 2|Rebecca 3|Jim ``` 創建表并插入三行。 ### 事務 在下一個示例中,我們將一些 SQL 語句放入事務中。 ```c #include <sqlite3.h> #include <stdio.h> int main(void) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } char *sql = "DROP TABLE IF EXISTS Friends;" "BEGIN TRANSACTION;" "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT);" "INSERT INTO Friends(Name) VALUES ('Tom');" "INSERT INTO Friends(Name) VALUES ('Rebecca');" "INSERT INTO Friends(Name) VALUES ('Jim');" "INSERT INTO Friend(Name) VALUES ('Robert');" "COMMIT;"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK ) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; } ``` 我們繼續使用`Friends`表。 ```c char *sql = "DROP TABLE IF EXISTS Friends;" "BEGIN TRANSACTION;" "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT);" "INSERT INTO Friends(Name) VALUES ('Tom');" "INSERT INTO Friends(Name) VALUES ('Rebecca');" "INSERT INTO Friends(Name) VALUES ('Jim');" "INSERT INTO Friend(Name) VALUES ('Robert');" "COMMIT;"; ``` 第一個語句刪除`Friends`表(如果存在)。 其他語句放在事務內。 事務以全有或全無的方式工作。 要么什么都不做,要么什么都不做。 ```c sqlite> .tables Cars Images ``` 由于最后一條語句有錯誤,因此將回滾事務,并且不會創建`Friends`表。 ## 數據來源 [SQLite 文檔](http://www.sqlite.org/docs.html)用于創建本教程。 [Tweet](https://twitter.com/share) 這是 SQLite C 教程。 ZetCode 擁有用于 SQLite Python 的完整電子書: [SQLite Python 電子書](/ebooks/sqlitepython/)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看