赞
踩
老林的C语言新课, 想快速入门点此 <C 语言编程核心突破>
sqlite3是文件型数据库, 小巧, 快, 环境构建容易. 本文介绍sqlite3最基本的C语言API, 有相关需求的人可以看看.
我们可以用最简单的sqlite3_exec( )函数完成sqlite3的命令输入, 通过调用callback函数操作返回的数据.
以下是函数原型:
SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
它接受五个参数:
sqlite3*:指向 SQLite 数据库的指针。
const char *sql:要执行的 SQL 命令。
int (callback)(void,int,char**,char**):指向回调函数的指针。如果不需要回调函数,则该参数可以为 NULL。
void *:回调函数的第一个参数。
char **errmsg:如果发生错误,则用于存储错误消息的指针。
当调用 sqlite3_exec 函数时,它将执行 SQL 命令并返回一个整数值,表示执行结果。如果执行成功,则返回 SQLITE_OK;如果发生错误,则返回其他值。
回调函数是一个可选参数,当执行 SQL 命令时,可以使用它来处理结果。
callback函数的简单定义, 这里没有使用第一个参数, 但这个参数非常重要, 可以将结果传出.
static int callback(void *data, int argc, char **argv, char **azColName)
{
for (int i = 0; i < argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
简单示例: 通过回调函数, 将股票代码为SH600000的所有数据进行打印
表的结构:
CREATE TABLE gupiaochi (
GuPiao text NOT NULL,
ShiJian text NOT NULL,
KaiPan real NOT NULL,
ZuiGao real NOT NULL,
ZuiDi real NOT NULL,
ShouPan real NOT NULL,
ZhangFu_pencent real NOT NULL,
ZhenFu_pencent real NOT NULL,
ZongShou int NOT NULL,
JinE int NOT NULL,
HuanShou_pencent real NOT NULL,
ChengJiaoCiShu int NOT NULL
);
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static int callback(void *data, int argc, char **argv, char **azColName)
{
static int index;
printf("%d\n", index++);
for (int i = 0; i < argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(936);
sqlite3 *dataBase;
int result = sqlite3_open("gupiao3.db", &dataBase);
if (result)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(dataBase));
exit(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
char *zErrMsg = NULL;
result = sqlite3_exec(
dataBase, "SELECT * FROM gupiaochi WHERE GuPiao LIKE 'SH600000';",
callback, 0, &zErrMsg);
return 0;
}
稍复杂示例: 存入数据:
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define BUFFERSIZE 1024
#define ARRSIZE 32
const char *guPiaoMingCheng[] = {
"SH600000浦发银行", "SH600004白云机场", "SH600009上海机场",
"SZ300601康泰生物", "SZ300628亿联网络", "SZ300676华大基因"};
const char *GbkToUtf8(const char *src_str)
{
if (strlen(src_str) >= BUFFERSIZE * 2 - 2)
{
return NULL;
}
static wchar_t wstr[BUFFERSIZE];
static char str[BUFFERSIZE * 3];
memset(wstr, 0, BUFFERSIZE);
memset(str, 0, (size_t)BUFFERSIZE * 3);
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, BUFFERSIZE);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, BUFFERSIZE * 3, NULL, NULL);
return str;
}
const char *Utf8ToGbk(const char *src_str)
{
if (strlen(src_str) >= BUFFERSIZE * 3 - 3)
{
return NULL;
}
static wchar_t wstr[BUFFERSIZE];
static char str[BUFFERSIZE * 3];
memset(wstr, 0, BUFFERSIZE);
memset(str, 0, (size_t)BUFFERSIZE * 3);
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wstr, BUFFERSIZE);
WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, BUFFERSIZE * 3, NULL, NULL);
return str;
}
static int callback(void *data, int argc, char **argv, char **azColName)
{
return 0;
}
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(936);
sqlite3 *dataBase;
char *zErrMsg = NULL;
int result = sqlite3_open("gupiao3.db", &dataBase);
if (result)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(dataBase));
exit(0);
}
else
{
fprintf(stdout, "Opened database successfully\n");
}
for (int i = 0; i != sizeof(guPiaoMingCheng) / sizeof(char *); ++i)
{
char path[BUFFERSIZE] = "E:\\C++\\other\\gupiao\\";
strcat(path, guPiaoMingCheng[i]);
// 含有中文, Windows只认GBK编码路径, 需要进行转换
FILE *dataFile = fopen(Utf8ToGbk(path), "r");
if (dataFile)
{
result = sqlite3_exec(dataBase, "BEGIN TRANSACTION;", callback, 0,
&zErrMsg);
static char line[BUFFERSIZE];
fgets(line, BUFFERSIZE, dataFile);
static char guPiao[ARRSIZE];
strncpy(guPiao, guPiaoMingCheng[i], 8);
static char shiJian[ARRSIZE];
static char kaiPanJiaGe[ARRSIZE];
static char zuiGaoJiaGe[ARRSIZE];
static char zuiDiJiaGe[ARRSIZE];
static char shouPanJiaGe[ARRSIZE];
static char zhangFu[ARRSIZE];
static char zhenFu[ARRSIZE];
static char zongShou[ARRSIZE];
static char jinE[ARRSIZE];
static char huanShou[ARRSIZE];
static char chengJiaoCiShu[ARRSIZE];
while (fgets(line, BUFFERSIZE, dataFile))
{
if (sscanf(GbkToUtf8(line), "%s%s%s%s%s%s%s%s%s%s%s", shiJian,
kaiPanJiaGe, zuiGaoJiaGe, zuiDiJiaGe, shouPanJiaGe,
zhangFu, zhenFu, zongShou, jinE, huanShou,
chengJiaoCiShu) != EOF)
{
static char sqlCommand[BUFFERSIZE];
sprintf(sqlCommand,
"INSERT INTO gupiaochi VALUES ('%s', '%s', %s, %s, "
"%s, %s, %s, %s, %s, %s, %s, %s );",
guPiao, shiJian, kaiPanJiaGe, zuiGaoJiaGe,
zuiDiJiaGe, shouPanJiaGe, zhangFu, zhenFu, zongShou,
jinE, huanShou, chengJiaoCiShu);
sqlite3_exec(dataBase, sqlCommand, callback, 0, &zErrMsg);
}
}
fclose(dataFile);
result = sqlite3_exec(dataBase, "COMMIT TRANSACTION;", callback, 0,
&zErrMsg);
if (result != SQLITE_OK)
{
fprintf(stderr, "%s\nSQL error: %s\n", guPiaoMingCheng[i],
zErrMsg);
sqlite3_free(zErrMsg);
}
else
{
fprintf(stdout, "Records created successfully\n");
}
}
}
sqlite3_close(dataBase);
return 0;
}
以上代码将如下格式的数据存入数据库:
时间 开盘 最高 最低 收盘 涨幅 振幅 总手 金额 换手 成交次数
2017-07-14五 15.67 18.94 15.67 18.94 +38.85 23.97 5500 106878 0.014 14
由于sqlite3只支持utf8, 需要将所有gbk编码的字符进行转换.
除了直接进行命令操作, 还可以进行分步操作, 这使得效率提升.
SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
该函数用于编译并预处理一条 SQL 语句,将其转换为 SQLite 内部的字节码表示。该函数接受四个参数:
db:数据库句柄,指向 SQLite 中打开的一个数据库。
zSql:要编译的 SQL 语句,以 UTF-8 编码。
nByte:zSql 的最大长度,以字节为单位。如果该值为 -1,则 SQLite 将自动计算 zSql 的长度。
ppStmt:一个指向 sqlite3_stmt 指针的指针,用于返回编译后的语句句柄。
pzTail:一个指向 const char 指针的指针,用于返回 zSql 中未使用的部分。
如果执行成功,sqlite3_prepare_v2 函数将返回 SQLITE_OK,同时将编译后的语句句柄存储在 ppStmt 所指向的指针中。
该句柄可以用于执行 SQL 语句,并且在使用完毕后需要通过 sqlite3_finalize 函数进行释放。
如果编译失败,该函数将返回相应的错误码,可以通过调用 sqlite3_errmsg 函数获取错误信息。
需要注意的是,sqlite3_prepare_v2 函数只对 SQL 语句进行编译和预处理,并不执行该语句。如果要执行 SQL 语句,应该使用 sqlite3_step 函数。
使用sqlite3_bind_text绑定sqlite3_prepare_v2中zSql的占位符
int sqlite3_bind_text(sqlite3_stmt*, //sql句柄
int, //要绑定的占位符序号, 占位符序号从1开始
const char*, //命令字符串
int, //命令字符串长度, -1为自动计算长度
void(*)(void*) //通常为NULL
);
sqlite3_prepare_v2准备一个命令, 用sqlite3_bind_text填充占位符 “?”
sqlite3_stmt *pstmt;
const char *sql = "SELECT* FROM gupiaochi WHERE GuPiao LIKE ?;";
result = sqlite3_prepare_v2(dataBase, sql, (int)strlen(sql), &pstmt, NULL);
result = sqlite3_bind_text(pstmt, 1, "SH600000", 8, NULL);
使用sqlite3_step进行分布查询:
函数原型, 查询一步
int sqlite3_step(sqlite3_stmt*);
查询一行, 打印一行, 并存入数组.
int index = 0;
while (sqlite3_step(pstmt) == SQLITE_ROW)
{
const unsigned char *guPiaoName = sqlite3_column_text(pstmt, 0);
const unsigned char *time = sqlite3_column_text(pstmt, 1);
double kaiPan = sqlite3_column_double(pstmt, 2);
printf("%d\t| %s\t| %s\t| %f\n", index, guPiaoName, time, kaiPan);
strcpy(guPiaoShuJuArr[index].GuPiao, (const char *)guPiaoName);
strcpy(guPiaoShuJuArr[index].ShiJian, (const char *)time);
guPiaoShuJuArr[index++].KaiPan = kaiPan;
}
以下函数获取查询一行后 iCol 列中的数据, 需要确定数据类型.
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
完整示例:
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define STRINGSIZE 16
typedef struct
{
char GuPiao[STRINGSIZE];
char ShiJian[STRINGSIZE];
double KaiPan;
} GuPiaoShuJu;
// 获取查询的第一个值, 存入 charArr
static int getCount(void *charArr, int argc, char **argv, char **azColName)
{
strcpy(charArr, argv[0]);
printf("%s\n", argv[0]);
return 0;
}
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(936);
sqlite3 *dataBase;
int result = sqlite3_open("gupiao3.db", &dataBase);
if (result)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(dataBase));
exit(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
char *zErrMsg = NULL;
char num[STRINGSIZE] = "";
result = sqlite3_exec(
dataBase,
"SELECT COUNT(*) FROM gupiaochi WHERE GuPiao LIKE 'SH600000';",
getCount, num, &zErrMsg);
int dataNum = atoi(num);
GuPiaoShuJu *guPiaoShuJuArr = malloc(sizeof(GuPiaoShuJu) * dataNum);
memset(guPiaoShuJuArr, 0, sizeof(GuPiaoShuJu) * dataNum);
sqlite3_stmt *pstmt;
const char *sql = "SELECT* FROM gupiaochi WHERE GuPiao LIKE ?;";
result = sqlite3_prepare_v2(dataBase, sql, (int)strlen(sql), &pstmt, NULL);
result = sqlite3_bind_text(pstmt, 1, "SH600000", 8, NULL);
int index = 0;
while (sqlite3_step(pstmt) == SQLITE_ROW)
{
const unsigned char *guPiaoName = sqlite3_column_text(pstmt, 0);
const unsigned char *time = sqlite3_column_text(pstmt, 1);
double kaiPan = sqlite3_column_double(pstmt, 2);
printf("%d\t| %s\t| %s\t| %f\n", index, guPiaoName, time, kaiPan);
strcpy(guPiaoShuJuArr[index].GuPiao, (const char *)guPiaoName);
strcpy(guPiaoShuJuArr[index].ShiJian, (const char *)time);
guPiaoShuJuArr[index++].KaiPan = kaiPan;
}
sqlite3_finalize(pstmt);
sqlite3_close(dataBase);
free(guPiaoShuJuArr);
return 0;
}
编译参数:
E:\msys64\clang64\bin\gcc.exe -ggdb addvalue4_01.c -o addvalue4_01 -L. -lsqlite3
sqlite3是使用最多的数据库, 因其短小精悍, 功能不弱, 为开发者所喜爱. 使用不难, 如果会sql语句以及C语言,很容易上手.
另外chitgpt现在也比较好用了, 查函数原型, 基本差不离, 这回没有出现自造函数的现象, 挺好.
老林的C语言新课, 想快速入门点此 <C 语言编程核心突破>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。