手机号归属地数据导入及查询工具源代码(C++)

手机归属地数据文件格式是自己定义的,格式描述如下:

手机号归属地数据导入及查询工具源代码(C++)_第1张图片

手机号段数据导入程序 C++ 源代码:
1. 自定义工具库头文件Global.h

#ifndef _MPGLOBAL_INCLUDED_ #define _MPGLOBAL_INCLUDED_ #pragma pack (1) //链表节点类 class StringNode { public: char * value; int length; int offset; StringNode * next; StringNode(const char * val); StringNode(); ~StringNode(); }; //索引表节点类 class IndexNode { public: int NumStart; int NumEnd; StringNode * Address; IndexNode * next; IndexNode(); IndexNode(int ns, int ne, StringNode * ad=NULL); }; //索引记录结构体 typedef struct _IndexStruct { int NumStart; int NumEnd; int Offset; } IndexStruct; //手机归属地结构体类型 typedef struct _MpLocation { int NumStart; int NumEnd; char * Location; } MpLocation; //更改文件扩展名 char * ChangeFileExt(const char * fn, const char * fext); //判断字符串是否为数字 bool IsNumeric(const char * val); #endif

 

2. 自定义工具库程序文件Global.cpp

 

#include <stdio.h> #include <string.h> #include "Global.h" StringNode::StringNode(const char * val) { this->length=strlen(val); this->value=new char[this->length+1]; strcpy(this->value,val); this->next=NULL; } StringNode::StringNode() { value=NULL; length=0; next=NULL; } StringNode::~StringNode() { if(value) delete[] value; } IndexNode::IndexNode() { NumStart=NumEnd=0; Address=NULL; next=NULL; } IndexNode::IndexNode(int ns, int ne, StringNode * ad) { NumStart=ns; NumEnd=ne; Address=ad; next=NULL; } char * ChangeFileExt(const char * fn, const char * fext) { int l=strlen(fn); int le=strlen(fext); for(int i=l-1; fn[i]!='.' && fn[i]!='//' && fn[i]!='/' && fn[i]!=':' && i>=0; i--); char * fnext; //如果没扩展名 if(i<=0||fn[i]=='/-:special:2:-||fn[i]=='/'||fn[i]==':') { fnext=new char[l+le+2]; strcpy(fnext,fn); fnext[l]='.'; l++; strcpy(fnext+l,fext); } else { l=i+1; fnext=new char[l+le+1]; strcpy(fnext,fn); strcpy(fnext+l,fext); } //申请新文件名的存储空间 return fnext; } bool IsNumeric(const char * val) { for(int i=0;val[i]!='/0';i++) { if(val[i]<'0'||val[i]>'9') return false; } return true; }

 

3. 主程序源文件 Mps.cpp

 

#include <stdio.h> #include <string.h> #include <conio.h> #include <windows.h> #include "Global.h" #define LINE_BUFFER_SIZE 256 //在字符串链表中搜索字符串,返回节点指针 inline StringNode * FindString(StringNode * st, const char * str) { for(StringNode * ps=st; ps!=NULL; ps=ps->next) { if(strcmp(ps->value,str)==0) return ps; } return NULL; } //文本数据 -> 二进制数据文件 void MpDataConvert(const char * fnin, const char * fnout) { FILE * fpin=fopen(fnin,"rb"); //输入文件 if(!fpin) { printf("打开文件失败!/n"); return; } printf("正在导入文件 [%s] 到 [%s] ... ",fnin,fnout); StringNode * stringTable; IndexNode * indexTable; StringNode * ps; IndexNode * p; int numLast; //上一行的号码 int numRead; //当前读取的号码 char * addrRead=new char[LINE_BUFFER_SIZE]; int sfCount=0; //源文件记录计数 bool isFirst=true; while(!feof(fpin)) { fscanf(fpin,"%d,%s",&numRead,addrRead); sfCount++; //首记录处理 if(isFirst) { ps=stringTable=new StringNode(addrRead); ps->next=NULL; p=indexTable=new IndexNode(numRead,0,ps); p->next=NULL; isFirst=false; //保存本次读取的号码以便读下一行时用到 numLast=numRead; continue; } //如果地址未变 if(strcmp(p->Address->value,addrRead)==0) { //保存本次读取的号码以便读下一行时用到 numLast=numRead; continue; } //如果地址变了 else { //完成前一条记录 p->NumEnd=numLast; //开始新记录 StringNode * s=FindString(stringTable,addrRead); if(s==NULL) { ps=ps->next=new StringNode(addrRead); s=ps; } p=p->next=new IndexNode(numRead,0,s); //保存本次读取的号码以便读下一行时用到 numLast=numRead; } } p->NumEnd=numLast; //关闭源文件 fclose(fpin); /***********************************************/ //FILE * fps=fopen("StringTable.txt","w"); int j=0; for(p=indexTable;p!=NULL;p=p->next) { //printf("%d %d %s/n",p->NumStart,p->NumEnd,p->Address->value); j++; } int k=0; for(ps=stringTable;ps!=NULL;ps=ps->next) { //printf("%s/n",ps->value); //fprintf(fps,"%s/n",ps->value); k++; } /***********************************************/ /***********************************************/ //导入数据文件 FILE * fpout=fopen(fnout,"wb"); int header[2]={0,0}; //文件头 fwrite(&header,sizeof(header),1,fpout); int pos=ftell(fpout); //写入字符串表 for(ps=stringTable;ps!=NULL;ps=ps->next) { pos=ftell(fpout); ps->offset=pos; fwrite(ps->value,1,ps->length+1,fpout); } //写入索引记录表 pos=ftell(fpout); header[0]=pos; IndexStruct is; for(p=indexTable;p!=NULL;p=p->next) { pos=ftell(fpout); is.NumStart=p->NumStart; is.NumEnd=p->NumEnd; is.Offset=p->Address->offset; fwrite(&is,sizeof(is)-1,1,fpout); } pos=ftell(fpout); header[1]=pos-(sizeof(is)-1); //重写文件头 fseek(fpout,0,SEEK_SET); fwrite(&header,sizeof(header),1,fpout); //获取数据文件大小 fseek(fpout,0,SEEK_END); pos=ftell(fpout); //关闭文件 fclose(fpout); printf("导入成功!/n"); printf("源文件记录数: %d/n",sfCount); printf("目标记录总数: %d/n",j); //fprintf(fps,"记录总数: %d/n",j); printf("字符串记录数: %d/n",k); //fprintf(fps,"字符串数: %d/n",k); //fclose(fps); printf("目标文件大小: %d字节/n",pos); /***********************************************/ //printf("/n按任意键退出..."); //getch(); } //获取号码段记录在文件中的偏移量 inline int getIndexOffset(FILE * fp, int fo, int lo, int num) { int mo; //中间偏移量 int mv; //中间值 int fv,lv; //边界值 int llv; //边界末末值 fseek(fp,fo,SEEK_SET); fread(&fv,sizeof(fv),1,fp); fseek(fp,lo,SEEK_SET); fread(&lv,sizeof(lv),1,fp); fread(&llv,sizeof(llv),1,fp); //边界检测处理 if(num<fv) return -1; else if(num>llv) return -1; //使用"二分法"确定记录偏移量 do { mo=fo+(lo-fo)/(sizeof(IndexStruct)-1)/2*(sizeof(IndexStruct)-1); fseek(fp,mo,SEEK_SET); fread(&mv,sizeof(mv),1,fp); if(num>=mv) fo=mo; else lo=mo; if(lo-fo==sizeof(IndexStruct)-1) mo=lo=fo; } while(fo!=lo); return mo; } //查询号码,返回号码段和归属地信息 MpLocation GetMpLocation(const char * fn, int num) { FILE * fp=fopen(fn,"rb"); if(!fp) throw "打开数据文件失败!"; int fo,lo; //读文件头,获取首末记录偏移量 fread(&fo,sizeof(fo),1,fp); fread(&lo,sizeof(lo),1,fp); int rcOffset=getIndexOffset(fp,fo,lo,num); MpLocation mpl; if(rcOffset>=0) { fseek(fp,rcOffset,SEEK_SET); //读取号码段起始地址和结束地址 fread(&mpl.NumStart,sizeof(mpl.NumStart),1,fp); fread(&mpl.NumEnd,sizeof(mpl.NumEnd),1,fp); //如果查询的号码处于中间空段 if(num>mpl.NumEnd) { mpl.NumStart=0; mpl.NumEnd=0; mpl.Location="未知地址"; } else { //读取字符串偏移量,3字节! int lstrOffset=0; fread(&lstrOffset,3,1,fp); lstrOffset&=0x00ffffff; fseek(fp,lstrOffset,SEEK_SET); //读取归属地字符串 static char strBuf[48]; fread(strBuf,sizeof(strBuf),1,fp); //检验字符串边界 for(int i=0;strBuf[i]!='/0'&&i<sizeof(strBuf);i++); if(i==sizeof(strBuf)) strBuf[sizeof(strBuf)-1]='/0'; mpl.Location=new char[strlen(strBuf)+1]; strcpy(mpl.Location,strBuf); } } else { //没找到记录 mpl.NumStart=0; mpl.NumEnd=0; mpl.Location="未知地址"; } fclose(fp); return mpl; } //号码查询程序 void MpLocating(const char * fn, char * sNum) { int num=0; if(!IsNumeric(sNum)) { printf("请输入7位手机号!/n"); } else { sscanf(sNum,"%7d",&num); try { MpLocation mpl=GetMpLocation(fn,num); printf("号码段: %07d - %07d/n",mpl.NumStart,mpl.NumEnd); printf("归属地: %s/n",mpl.Location); } catch(char * e) { printf("%s/n",e); } } } //显示帮助信息 inline void printHelp() { const char * en="Mps"; printf("手机归属地查询程序./n/n"); printf("查询归属地: %s <号码前七位>/n",en); printf("导入数据库: %s -c <数据源文件名>/n",en); printf("/n示例:/n"); printf(" > %s -c MpData.txt 导入MpData.txt到MpData.dat/n",en); printf(" > %s 1358348 查询号段1358348的归属地/n",en); printf("/n提示: 查询归属地时请把数据库文件MpData.dat与本程序放在同一目录下./n"); } //===================主程序入口=================== void main(int argc, char * argv[]) { /*********************************************************** argc=2; argv[0]="Mps.exe"; argv[1]="MpLocator.txt"; ************************************************************/ //数据文件名 const char * fnData="MpData.dat"; if(argc>1) { char opcode='s'; //操作码 's'为查询号码, 'c'为导入数据 char * val=""; //参数值 //获取操作码和参数值 for(int i=1;i<argc;i++) { if(argv[i][0]=='-') opcode=argv[i][1]; else val=argv[i]; } //操作选择 switch(opcode) { case 's': //查询号码 MpLocating(fnData,val); break; case 'c': //导入数据 MpDataConvert(val,ChangeFileExt(val,"dat")); break; case 'h': //帮助信息 printHelp(); break; default: //无操作 break; } } else { //直接双击运行 char inputBuf[32]; while(true) { printf("手机号前7位: "); fgets(inputBuf,32,stdin); if(inputBuf[strlen(inputBuf)-1]=='/n') inputBuf[strlen(inputBuf)-1]='/0'; //如果接收到空字符串则退出 if(strlen(inputBuf)==0) break; MpLocating(fnData,inputBuf); printf("/n"); } //保持屏幕5秒钟 //Sleep(5000); } }

完整的源代码及数据文件请从这里下载: http://download.csdn.net/source/611741

你可能感兴趣的:(C++,header,null,手机,工具,FP)