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

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

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

  1. #ifndef _MPGLOBAL_INCLUDED_
  2. #define _MPGLOBAL_INCLUDED_
  3. #pragma pack (1)
  4. //链表节点类
  5. class StringNode
  6. {
  7. public:
  8.     char * value;
  9.     int length;
  10.     int offset;
  11.     StringNode * next;
  12.     StringNode(const char * val);
  13.     StringNode();
  14.     ~StringNode();
  15. };
  16. //索引表节点类
  17. class IndexNode
  18. {
  19. public:
  20.     int NumStart;
  21.     int NumEnd;
  22.     StringNode * Address;
  23.     IndexNode * next;
  24.     IndexNode();
  25.     IndexNode(int ns, int ne, StringNode * ad=NULL);
  26. };
  27. //索引记录结构体
  28. typedef struct _IndexStruct
  29. {
  30.     int NumStart;
  31.     int NumEnd;
  32.     int Offset;
  33. } IndexStruct;
  34. //手机归属地结构体类型
  35. typedef struct _MpLocation
  36. {
  37.     int NumStart;
  38.     int NumEnd;
  39.     char * Location;
  40. } MpLocation;
  41. //更改文件扩展名
  42. char * ChangeFileExt(const char * fn, const char * fext);
  43. //判断字符串是否为数字
  44. bool IsNumeric(const char * val);
  45. #endif

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

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "Global.h"
  4. StringNode::StringNode(const char * val)
  5. {
  6.     this->length=strlen(val);
  7.     this->value=new char[this->length+1];
  8.     strcpy(this->value,val);
  9.     this->next=NULL;
  10. }
  11. StringNode::StringNode()
  12. {
  13.     value=NULL;
  14.     length=0;
  15.     next=NULL;
  16. }
  17. StringNode::~StringNode()
  18. {
  19.     if(value) delete[] value;
  20. }
  21. IndexNode::IndexNode()
  22. {
  23.     NumStart=NumEnd=0;
  24.     Address=NULL;
  25.     next=NULL;
  26. }
  27. IndexNode::IndexNode(int ns, int ne, StringNode * ad)
  28. {
  29.     NumStart=ns; NumEnd=ne; Address=ad;
  30.     next=NULL;
  31. }
  32. char * ChangeFileExt(const char * fn, const char * fext)
  33. {
  34.     int l=strlen(fn);
  35.     int le=strlen(fext);
  36.     for(int i=l-1; fn[i]!='.' && fn[i]!='//' && fn[i]!='/' && fn[i]!=':' && i>=0; i--);
  37.     char * fnext;
  38.     //如果没扩展名
  39.     if(i<=0||fn[i]=='/-:special:2:-||fn[i]=='/'||fn[i]==':')
  40.     {
  41.         fnext=new char[l+le+2];
  42.         strcpy(fnext,fn);
  43.         fnext[l]='.';
  44.         l++;
  45.         strcpy(fnext+l,fext);
  46.     }
  47.     else
  48.     {
  49.         l=i+1;
  50.         fnext=new char[l+le+1];
  51.         strcpy(fnext,fn);
  52.         strcpy(fnext+l,fext);
  53.     }
  54.     //申请新文件名的存储空间
  55.     return fnext;
  56. }
  57. bool IsNumeric(const char * val)
  58. {
  59.     for(int i=0;val[i]!='/0';i++)
  60.     {
  61.         if(val[i]<'0'||val[i]>'9')
  62.             return false;
  63.     }
  64.     return true;
  65. }

3. 主程序源文件 Mps.cpp

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <conio.h>
  4. #include <windows.h>
  5. #include "Global.h"
  6. #define LINE_BUFFER_SIZE 256
  7. //在字符串链表中搜索字符串,返回节点指针
  8. inline StringNode * FindString(StringNode * st, const char * str)
  9. {
  10.     for(StringNode * ps=st; ps!=NULL; ps=ps->next)
  11.     {
  12.         if(strcmp(ps->value,str)==0)
  13.             return ps;
  14.     }
  15.     return NULL;
  16. }
  17. //文本数据 -> 二进制数据文件
  18. void MpDataConvert(const char * fnin, const char * fnout)
  19. {
  20.     FILE * fpin=fopen(fnin,"rb");     //输入文件
  21.     if(!fpin)
  22.     {
  23.         printf("打开文件失败!/n");
  24.         return;
  25.     }
  26.     printf("正在导入文件 [%s] 到 [%s] ... ",fnin,fnout);
  27.     StringNode * stringTable;
  28.     IndexNode * indexTable;
  29.     StringNode * ps;
  30.     IndexNode * p;
  31.     int numLast;   //上一行的号码
  32.     int numRead;   //当前读取的号码
  33.     char * addrRead=new char[LINE_BUFFER_SIZE];
  34.     int sfCount=0; //源文件记录计数
  35.     bool isFirst=true;
  36.     while(!feof(fpin))
  37.     {
  38.         fscanf(fpin,"%d,%s",&numRead,addrRead); sfCount++;
  39.         //首记录处理
  40.         if(isFirst)
  41.         {
  42.             ps=stringTable=new StringNode(addrRead);
  43.             ps->next=NULL;
  44.             p=indexTable=new IndexNode(numRead,0,ps);
  45.             p->next=NULL;
  46.             isFirst=false;
  47.             //保存本次读取的号码以便读下一行时用到
  48.             numLast=numRead;
  49.             continue;
  50.         }
  51.         //如果地址未变
  52.         if(strcmp(p->Address->value,addrRead)==0)
  53.         {
  54.             //保存本次读取的号码以便读下一行时用到
  55.             numLast=numRead;
  56.             continue;
  57.         }
  58.         //如果地址变了
  59.         else
  60.         {
  61.             //完成前一条记录
  62.             p->NumEnd=numLast;
  63.             //开始新记录
  64.             StringNode * s=FindString(stringTable,addrRead);
  65.             if(s==NULL)
  66.             {
  67.                 ps=ps->next=new StringNode(addrRead);
  68.                 s=ps;
  69.             }
  70.             p=p->next=new IndexNode(numRead,0,s);
  71.             //保存本次读取的号码以便读下一行时用到
  72.             numLast=numRead;
  73.         }
  74.     }
  75.     p->NumEnd=numLast;
  76.     //关闭源文件
  77.     fclose(fpin);
  78.     /***********************************************/
  79.     //FILE * fps=fopen("StringTable.txt","w");
  80.     int j=0;
  81.     for(p=indexTable;p!=NULL;p=p->next)
  82.     {
  83.         //printf("%d %d  %s/n",p->NumStart,p->NumEnd,p->Address->value);
  84.         j++;
  85.     }
  86.     int k=0;
  87.     for(ps=stringTable;ps!=NULL;ps=ps->next)
  88.     {
  89.         //printf("%s/n",ps->value);
  90.         //fprintf(fps,"%s/n",ps->value);
  91.         k++;
  92.     }
  93.     /***********************************************/
  94.     /***********************************************/
  95.     //导入数据文件
  96.     FILE * fpout=fopen(fnout,"wb");
  97.     int header[2]={0,0};  //文件头
  98.     fwrite(&header,sizeof(header),1,fpout);
  99.     int pos=ftell(fpout);
  100.     //写入字符串表
  101.     for(ps=stringTable;ps!=NULL;ps=ps->next)
  102.     {
  103.         pos=ftell(fpout);
  104.         ps->offset=pos;
  105.         fwrite(ps->value,1,ps->length+1,fpout);
  106.     }
  107.     //写入索引记录表
  108.     pos=ftell(fpout);
  109.     header[0]=pos;
  110.     IndexStruct is;
  111.     for(p=indexTable;p!=NULL;p=p->next)
  112.     {
  113.         pos=ftell(fpout);
  114.         is.NumStart=p->NumStart;
  115.         is.NumEnd=p->NumEnd;
  116.         is.Offset=p->Address->offset;
  117.         fwrite(&is,sizeof(is)-1,1,fpout);
  118.     }
  119.     pos=ftell(fpout);
  120.     header[1]=pos-(sizeof(is)-1);
  121.     //重写文件头
  122.     fseek(fpout,0,SEEK_SET);
  123.     fwrite(&header,sizeof(header),1,fpout);
  124.     //获取数据文件大小
  125.     fseek(fpout,0,SEEK_END);
  126.     pos=ftell(fpout);
  127.     //关闭文件
  128.     fclose(fpout);
  129.     printf("导入成功!/n");
  130.     printf("源文件记录数: %d/n",sfCount);
  131.     printf("目标记录总数: %d/n",j);
  132.     //fprintf(fps,"记录总数: %d/n",j);
  133.     printf("字符串记录数: %d/n",k);
  134.     //fprintf(fps,"字符串数: %d/n",k);
  135.     //fclose(fps);
  136.     printf("目标文件大小: %d字节/n",pos);
  137.     /***********************************************/
  138.     //printf("/n按任意键退出...");
  139.     //getch();
  140. }
  141. //获取号码段记录在文件中的偏移量
  142. inline int getIndexOffset(FILE * fp, int fo, int lo, int num)
  143. {
  144.     int mo;    //中间偏移量
  145.     int mv;    //中间值
  146.     int fv,lv; //边界值
  147.     int llv;   //边界末末值
  148.     fseek(fp,fo,SEEK_SET);
  149.     fread(&fv,sizeof(fv),1,fp);
  150.     fseek(fp,lo,SEEK_SET);
  151.     fread(&lv,sizeof(lv),1,fp);
  152.     fread(&llv,sizeof(llv),1,fp);
  153.     //边界检测处理
  154.     if(num<fv)
  155.         return -1;
  156.     else if(num>llv)
  157.         return -1;
  158.     //使用"二分法"确定记录偏移量
  159.     do
  160.     {
  161.         mo=fo+(lo-fo)/(sizeof(IndexStruct)-1)/2*(sizeof(IndexStruct)-1);
  162.         fseek(fp,mo,SEEK_SET);
  163.         fread(&mv,sizeof(mv),1,fp);
  164.         if(num>=mv)
  165.             fo=mo;
  166.         else
  167.             lo=mo;
  168.         if(lo-fo==sizeof(IndexStruct)-1)
  169.             mo=lo=fo;
  170.     } while(fo!=lo);
  171.     return mo;
  172. }
  173. //查询号码,返回号码段和归属地信息
  174. MpLocation GetMpLocation(const char * fn, int num)
  175. {
  176.     FILE * fp=fopen(fn,"rb");
  177.     if(!fp)
  178.         throw "打开数据文件失败!";
  179.     int fo,lo;
  180.     //读文件头,获取首末记录偏移量
  181.     fread(&fo,sizeof(fo),1,fp);
  182.     fread(&lo,sizeof(lo),1,fp);
  183.     int rcOffset=getIndexOffset(fp,fo,lo,num);
  184.     MpLocation mpl;
  185.     if(rcOffset>=0)
  186.     {
  187.         fseek(fp,rcOffset,SEEK_SET);
  188.         //读取号码段起始地址和结束地址
  189.         fread(&mpl.NumStart,sizeof(mpl.NumStart),1,fp);
  190.         fread(&mpl.NumEnd,sizeof(mpl.NumEnd),1,fp);
  191.         //如果查询的号码处于中间空段
  192.         if(num>mpl.NumEnd)
  193.         {
  194.             mpl.NumStart=0; mpl.NumEnd=0;
  195.             mpl.Location="未知地址";
  196.         }
  197.         else
  198.         {
  199.             //读取字符串偏移量,3字节!
  200.             int lstrOffset=0;
  201.             fread(&lstrOffset,3,1,fp);
  202.             lstrOffset&=0x00ffffff;
  203.             fseek(fp,lstrOffset,SEEK_SET);
  204.             //读取归属地字符串
  205.             static char strBuf[48];
  206.             fread(strBuf,sizeof(strBuf),1,fp);
  207.             //检验字符串边界
  208.             for(int i=0;strBuf[i]!='/0'&&i<sizeof(strBuf);i++);
  209.             if(i==sizeof(strBuf)) strBuf[sizeof(strBuf)-1]='/0';
  210.             mpl.Location=new char[strlen(strBuf)+1];
  211.             strcpy(mpl.Location,strBuf);
  212.         }
  213.     }
  214.     else
  215.     {
  216.         //没找到记录
  217.         mpl.NumStart=0; mpl.NumEnd=0;
  218.         mpl.Location="未知地址";
  219.     }
  220.     fclose(fp);
  221.     return mpl;
  222. }
  223. //号码查询程序
  224. void MpLocating(const char * fn, char * sNum)
  225. {
  226.     int num=0;
  227.     if(!IsNumeric(sNum))
  228.     {
  229.         printf("请输入7位手机号!/n");
  230.     }
  231.     else
  232.     {
  233.         sscanf(sNum,"%7d",&num);
  234.         try
  235.         {
  236.             MpLocation mpl=GetMpLocation(fn,num);
  237.             printf("号码段: %07d - %07d/n",mpl.NumStart,mpl.NumEnd);
  238.             printf("归属地: %s/n",mpl.Location);
  239.         }
  240.         catch(char * e)
  241.         {
  242.             printf("%s/n",e);
  243.         }
  244.     }
  245. }
  246. //显示帮助信息
  247. inline void printHelp()
  248. {
  249.     const char * en="Mps";
  250.     printf("手机归属地查询程序./n/n");
  251.     printf("查询归属地: %s <号码前七位>/n",en);
  252.     printf("导入数据库: %s -c <数据源文件名>/n",en);
  253.     printf("/n示例:/n");
  254.     printf("   > %s -c MpData.txt              导入MpData.txt到MpData.dat/n",en);
  255.     printf("   > %s 1358348                    查询号段1358348的归属地/n",en);
  256.     printf("/n提示: 查询归属地时请把数据库文件MpData.dat与本程序放在同一目录下./n");
  257. }
  258. //===================主程序入口===================
  259. void main(int argc, char * argv[])
  260. {
  261.     /***********************************************************
  262.     argc=2;
  263.     argv[0]="Mps.exe";
  264.     argv[1]="MpLocator.txt";
  265.     ************************************************************/
  266.     //数据文件名
  267.     const char * fnData="MpData.dat";
  268.     if(argc>1)
  269.     {
  270.         char opcode='s';  //操作码 's'为查询号码, 'c'为导入数据
  271.         char * val="";    //参数值
  272.         //获取操作码和参数值
  273.         for(int i=1;i<argc;i++)
  274.         {
  275.             if(argv[i][0]=='-')
  276.                 opcode=argv[i][1];
  277.             else
  278.                 val=argv[i];
  279.         }
  280.         //操作选择
  281.         switch(opcode)
  282.         {
  283.         case 's':
  284.             //查询号码
  285.             MpLocating(fnData,val);
  286.             break;
  287.         case 'c':
  288.             //导入数据
  289.             MpDataConvert(val,ChangeFileExt(val,"dat"));
  290.             break;
  291.         case 'h':
  292.             //帮助信息
  293.             printHelp();
  294.             break;
  295.         default:
  296.             //无操作
  297.             break;
  298.         }
  299.     }
  300.     else
  301.     {
  302.         //直接双击运行
  303.         char inputBuf[32];
  304.         while(true)
  305.         {
  306.             printf("手机号前7位: ");
  307.             fgets(inputBuf,32,stdin);
  308.             if(inputBuf[strlen(inputBuf)-1]=='/n')
  309.                 inputBuf[strlen(inputBuf)-1]='/0';
  310.             //如果接收到空字符串则退出
  311.             if(strlen(inputBuf)==0)
  312.                 break;
  313.             MpLocating(fnData,inputBuf);
  314.             printf("/n");
  315.         }
  316.         //保持屏幕5秒钟
  317.         //Sleep(5000);
  318.     }
  319. }

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

 

  (原创文章,转载时请注明本文网址)

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值