从数据库中查找单词

我们知道,从文件中查找是一行一行的查找匹配,但是数据库就可以快速查找,节约时间;

我们先来讲一下大概思路(所有都为C语言);

首先使用access函数判断数据库字典有没有被创建,如果创建了就跳过创建这个步骤,要不然每次加载都会耗费很多时间(几乎1-2分钟)(等待的过程蛮漫长的);

这是使用到的头文件;

#include <sqlite3.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
/*********************定义的全局变量函数***************/
sqlite3 *pdb;
char temp[4096] = {0};
char *errmsg = NULL;

这是主函数的逻辑;

int main(void)
{
    int ret = 0;
    int ok = 0;

    ok = access("/home/linux/Desktop/2024/20240822/dict.db",F_OK); //这个路径是我自己的,可以替换
    if(0 == ok)  //access函数的特性,F_OK是用于查看该文件是否存在,成功返回0
    {
        ret = Open();  //打开数据库
        if(ret == -1)  //错误处理
        {
            fprintf(stderr,"fail to sqlite_open:%s\n",sqlite3_errmsg(pdb));
            return -1;
        }
        ret = word_put();  //传入想要查询的单词
        if(ret == -1)        //错误处理
        {
            fprintf(stderr,"fail to sqlite_exec:%s\n",errmsg);
            sqlite3_free(errmsg);   //释放掉错误码的空间
            sqlite3_close(pdb);    //关闭数据库
            return -1;
        }
        return 0;
    }

    if(-1 == ok)
    {
        printf("不存在,开始创建\n");
        ret = Open();
        if(ret == -1)
        {
            fprintf(stderr,"fail to sqlite_open:%s\n",sqlite3_errmsg(pdb));
            return -1;
        }
        ret = word_creat();
        if(ret == -1)
        {
            return -1;
        }
        ret = word_put();
        if(ret == -1)
        {
            fprintf(stderr,"fail to sqlite_exec:%s\n",errmsg);
            sqlite3_free(errmsg);
            sqlite3_close(pdb);
            return -1;
        }
    }
    sqlite3_close(pdb);
    return 0;
}

打开数据库的函数;

/****************************************************/
int Open(void)
{
    int ret = 0;
    ret = sqlite3_open("dict.db",&pdb);
    if(ret != SQLITE_OK)
    {
        return -1;
    }
    return 0;
}
/*****************************************************/

创建dict 数据库,并将字典加载到数据库中;

/*************************************************/
int word_creat()
{
    int ret = 0;
    FILE *fp = NULL;;
    char *nsize = NULL;
    char *pword = NULL;
    char *pmean = NULL;
    char tempword[1024] = {0};
    sprintf(temp,"create table dict(id integer primary key asc, word text, mean text)");
    ret = sqlite3_exec(pdb,temp,NULL,NULL,&errmsg); //使用sqlite3_exec函数执行语句
    if(ret != SQLITE_OK)  //错误处理
    {
        fprintf(stderr,"fail to sqlite_exec:%s\n",errmsg);
        sqlite3_free(errmsg);
        sqlite3_close(pdb);
        return -1;
    }
    fp = fopen("dict.txt","r");  //打开字典文件
    if(NULL == fp)
    {
        perror("fail to fopen dict.txt");
        sqlite3_close(pdb);
        return -1;
    }

    while(1)
    {
        memset(temp,0,sizeof(temp));   //对temp清零
        nsize = fgets(temp,sizeof(temp),fp);  //读取一行字符串
        temp[strlen(temp)-1] = '\0';
        if(nsize == NULL)
        {
            break;
        }
        pword = strtok(temp," ");   //进行分割
        pmean = strtok(NULL,"\r\n");
        sprintf(tempword,"insert into dict values (NULL,\"%s\",\"%s\")",pword,pmean);
        ret = sqlite3_exec(pdb,tempword,NULL,NULL,&errmsg);  //插入单词和含义
        if(ret != SQLITE_OK)
        {
            fprintf(stderr,"fail to sqlite_exec11:%s\n",errmsg);
            sqlite3_free(errmsg);
            sqlite3_close(pdb);
            return -1;
        }
    }
    fclose(fp);  
    return 0;
}
/*****************************************************/

查询单词;

/*****************************************************/
int word_put(void)
{
    int ret = 0;
    char input[1024] = {0};
    printf("录入完成!\n");
    memset(temp,0,sizeof(temp));
    fgets(temp,sizeof(temp),stdin);
    temp[strlen(temp)-1] = '\0';
    sprintf(input,"select word ,mean from dict where word = \"%s\"",temp);
    ret = sqlite3_exec(pdb,input,callback,NULL,&errmsg);
    if(ret != SQLITE_OK)
    {
        return -1;
    }
    return 0;
}
/*************************************************/

回调函数;

/**************************************************/
int callback(void * arg, int column, char **pcontet, char **ptitle)
{
    printf("%s : %s\n",pcontet[0],pcontet[1]);  //打印查到的单词和意思
    return 0;
}
/****************************************************/

这里面有几个有意思的点:

1.字符串的分割;

        因为原字典里的单词长这样:a                indef art one \r\n,

        用strtok分割,第一次分割空格之前的单词,第二次分割到\r\n;

2.在加载过程中显示加载进度;

        由于加载过程中太无聊,想要一点动态显示加载进度可以这样做,

//加载单词文件时,fseek将光标偏移到最末尾      

    fseek(fp, 0, SEEK_END);

//ftell获得光表的偏移量

    tlen = ftell(fp);

//再将光标定义回开头

    rewind(fp);

这样就获得了整个文件的大小;

//读取一行信息

        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);

//获得这一行的大小

        clen = ftell(fp);

//转换成double型打印

        printf("已加载: %.2lf\r", (double)clen / (double)tlen * 100);

//刷新

        fflush(fp);

加上循环,这样就可以动态显示加载进度了;

3.显示加载用时;

想要显示整个文件加载到数据库需要多长时间可以这样做;

在加载文件之前使用gettimeofday; 

gettimeofday(&start, NULL);

在加载文件完成后使用;

 gettimeofday(&end, NULL);


打印;
printf("加载数据库文件成功! 耗时: %.2lf s  CPU耗时:%.2lf s\n", ((double)(end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec)) / 1000000,((double)(cpuend - cpustart)) / CLOCKS_PER_SEC);

4.使用makefile

因为这个程序调用了sqlite3库,所以在编译时需要加上 -lsqlite3,要是每次都加可能比较麻烦,所以我们创建makefile文件;

.PHONY:是一个伪指令,

a.out:select_world.c
	gcc $^ -o $@ -lsqlite3
.PHONY:
clean:
	rm a.out

5.如何将加载时间压缩到极致;

第一种方法:关闭磁盘写同步

        PRAGMA synchronous = NORMAL;

第二种方法:开启事务

        begin 和 commit;

第三种办法:使用预处理SQL语句机制实现提升数据库效率

今天就到这里啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值