当当网泄露的数据1.1G,共有13180805条记录,在内存使用的较小的情况下实现快速检索。这里使用QT(方面做图形界面),读写文件则使用C语言的相关库函数。
1.使用普通方法检索,就是一行一行的读取文件,然后再判断该行信息是否符合要求。
2.根据键值建立索引文件,然后查询的时候根据输入姓名键值转换对应到相应的索引文件中去查找。
一个汉字占两个字节:使用汉字两个字即4个字节对应的ASCII之和对256 求余得索引值(index=((unsignedchar)p[0]+(unsignedchar)p[1]+(unsignedchar)p[2]+(unsignedchar)p[3])%256;),查找先根据key值得前两个汉字得到索引值在对应小的索引文件中进行查找,此时使用fread一把将索引文件内容读到内存,避免了使用fgets()函数一行一行读取调用函数的时间开销。
当当网数据.txt:链接:https://pan.baidu.com/s/1kUk6XAv 密码:5nbr
首先使用Logview 这个软件来打开数据(记事本打不开),则实现根据人名快速检索其基本信息。
使用普通方法检索,就是一行一行的读取文件,然后再判断该行信息是否符合要求。
下面是建立索引后的检索
对比可以看出:查询时间是不是提高了100倍。
主要代码:
#include "widget.h"
#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QMessageBox>
#include<QTextCodec>
#include<time.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<direct.h>
#include<windows.h>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
file_length_label =new QLabel;
query_label = new QLabel;
edit =new QLineEdit;
search_btn = new QPushButton;
text_browser = new QTextBrowser;
search_btn->setText("查询");
setWindowTitle("当当数据查询");
file_length_label->setText("文件大小1.1G.");
query_label->setText("输入查询姓名:");
QHBoxLayout *h_box_layout = new QHBoxLayout;
h_box_layout->addWidget(query_label);
h_box_layout->addWidget(edit);
h_box_layout->addWidget(search_btn);
QVBoxLayout *v_box_layout=new QVBoxLayout(this);
v_box_layout->addWidget(file_length_label);
v_box_layout->addLayout(h_box_layout);
v_box_layout->addWidget(text_browser);
connect(search_btn,SIGNAL(clicked()),this,SLOT(on_click()));//将button和on_click()方法关联
}
Widget::~Widget()
{
}
void Widget::on_click()
{
//create_index(); //创建索引文件
// select(); //普通的查找
select_use_index();
}
int Widget::select_use_index()
{
clock_t start= clock();
this->setCursor(Qt::WaitCursor);//设置光标为等待状态
unsigned long count =0;
char *pbegin = NULL,*pend = NULL,*pmove = NULL;
char *buffer =NULL;
unsigned int size = 0;
char file_name[100]={0};
char key[50] ={0};
char content[1024]={0};
text_browser->clear();
//QT 字符串默认为Unicode编码所以要进行转换
QTextCodec *codec = QTextCodec::codecForName("GBK");
if(get_key(key)<4)
{
QMessageBox::information(this,"提示","请输正确的查询信息!");
return -1;
}
key[strlen(key)]=',';
int index=((unsigned char)key[0]+(unsigned char)key[1]+(unsigned char)key[2]+(unsigned char)key[3])%256;
sprintf(file_name,"%s%d%s","E://index//",index,".db");//通过索引查找
if((size=load_file(file_name,&buffer))<=0)
{
return 0;
}
pmove = buffer;
while(pmove<buffer+size)
{
pbegin=pmove;
pmove=strchr(pmove,',');
pend=strchr(pmove,'\n');
if(!pend)//读到最后一行情况
{
pend=strchr(pmove,0);
if(!pend)
{
break;
}
}
if(strncmp(key,pmove+1,strlen(key))==0)
{
count++;
memcpy(content,pbegin,pend-pbegin);
text_browser->append(codec->toUnicode(content));
memset(content,0,sizeof(content));
}
pmove=pend+1;
}
clock_t end= clock();
QString res="一共找到记录:"+QString::number(count)+"条,耗时:"+QString::number(end-start)+"ms";
this->setCursor(Qt::ArrowCursor);//设置光标为箭头状态
QMessageBox::information(this,"提示",res);
free(buffer);
return 0;
}
int Widget::select()
{
clock_t start= clock();
unsigned long long count =0;
char *pline = NULL;
char key[50] ={0};
int len =0;
char content[1024]={0};
text_browser->clear();
QTextCodec *codec = QTextCodec::codecForName("GBK");
//将输入内容转换为与文件相同的的编码方式
if(get_key(key)<4)
{
QMessageBox::information(this,"提示","请输正确的查询信息!");
return -1;
}
key[strlen(key)]=',';
FILE *fp=fopen(codec->fromUnicode("E://当当.txt").data(), "rb");
while(!feof(fp))
{
memset(content,0,sizeof(content));
fgets(content,sizeof(content),fp);
len = strlen(content);
if(len<5)//防止文件结尾有回车符
{
break;
}
pline = strchr(content,',')+1;
if(strncmp(key,pline,strlen(key))==0)
{
count++;
text_browser->append(codec->toUnicode(content));
}
}
clock_t end= clock();
fclose(fp);
QString res="一共找到记录:"+QString::number(count)+"条,耗时:"+QString::number(end-start)+"ms";
this->setCursor(Qt::ArrowCursor);//设置光标为箭头状态
QMessageBox::information(this,"提示",res);
return 0;
}
unsigned int Widget::load_file(const char *file_name,char **buffer)
{
FILE *fp=fopen(file_name, "rb");
if(fp==NULL)
{
QMessageBox::information(this,"提示","文件打开失败");
return 0;
}
fseek(fp, 0, SEEK_END);
unsigned int size = (unsigned)ftell(fp);
rewind(fp);
*buffer = (char*)malloc(sizeof(char)*(size));
fread(*buffer, 1, size, fp); // 将文件一把读入到内存,可以减少系统调用时间
fclose(fp);
return size;
}
int Widget::get_key(char *key)
{
QTextCodec *codec = QTextCodec::codecForName("GBK");//因为文件文件GBK编码的txt文件
//将输入内容转换为与文件相同的的编码方式
const char *str=codec->fromUnicode(edit->text().trimmed()).data();
strcpy(key,str);
return strlen(key);
}
int Widget::create_index()
{
this->setCursor(Qt::WaitCursor);
FILE *fp_array[256];
char file_name[50];
char *p;
int len = 0;
int index;
QTextCodec *codec = QTextCodec::codecForName("GBK");
clock_t start= clock();
char content[1024]={0};
FILE *fp=fopen(codec->fromUnicode("E://当当.txt").data(), "rb");
if(fp==NULL)
{
QMessageBox::information(this,"提示","文件打开失败");
return 0;
}
for(int i=0;i<256;i++)
{
sprintf(file_name,"%s%d%s","E://index//",i,".db");
fp_array[i] = fopen(file_name,"w");
}
while(!feof(fp))
{
memset(content,0,sizeof(content));
fgets(content,sizeof(content),fp);
len = strlen(content);
if(len<5)//防止文件结尾有回车符
{
break;
}
p = strchr(content,',')+1;
index=((unsigned char)p[0]+(unsigned char)p[1]+(unsigned char)p[2]+(unsigned char)p[3])%256;
fputs(content,fp_array[index]);//将该行内容写到对应的索引文件中
}
clock_t end= clock();
for(int i=0;i<256;i++)
{
fclose(fp_array[i]);
}
fclose(fp);
QString res="建立索引耗时:"+QString::number(end-start)+"ms";
this->setCursor(Qt::ArrowCursor);
QMessageBox::information(this,"提示",res);
return 0;
}
code:http://download.csdn.net/detail/huangshanchun/8553757