您的位置:首页 > 编程语言 > C语言/C++

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

2010-03-22 10:58 886 查看
手机归属地数据文件格式是自己定义的,格式描述如下:



手机号段数据导入程序 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++ fp header null