本文整理自网络,侵删。
手机号码库段号地区查询
一个用 Delphi 解析的手机号码库 例子,虽然现在可以手机号码不换号转网了,但可以用来学习 Delphi 流文件解析。和二叉树的快速查询
数据库来源:https://github.com/ls0f/phone
phone.dat文件格式
| 4 bytes | <- phone.dat 版本号 ------------ | 4 bytes | <- 第一个索引的偏移 ----------------------- | offset - 8 | <- 记录区 ----------------------- | index | <- 索引区 -----------------------
头部 头部为8个字节,版本号为4个字节,第一个索引的偏移为4个字节(<4si)。记录区 中每条记录的格式为"<省份>|<城市>|<邮编>|<长途区号>\0"。 每条记录以'\0'结束。索引区 中每条记录的格式为"<手机号前七位><记录区的偏移><卡类型>",每个索引的长度为9个字节(<iiB)。解析步骤:
解析头部8个字节,得到索引区的第一条索引的偏移。在索引区用二分查找得出手机号在记录区的记录偏移。在记录区从上一步得到的记录偏移处取数据,直到遇到'\0'。卡类型定义:
1 移动2 联通3 电信4 电信虚拟运营商5 联通虚拟运营商6 移动虚拟运营商
unit Unit1;
interface
uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants , System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms , Vcl.Dialogs, Vcl.StdCtrls;
type
TPhone = class(TObject) private FStm: TStringStream; FVersion: String; //版本号 FOffset: Cardinal; //起始偏移 public function Find(const AStr7: String): String; constructor Create(); destructor Destroy; override; procedure LoadFromFile(const FileName: string); property Version: String read FVersion; end;
TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } f: TPhone; public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
uses StrUtils;
procedure TForm1.FormCreate(Sender: TObject);begin f:= TPhone.Create; f.LoadFromFile(ExtractFilePath(ParamStr(0))+'phone.dat');end;
procedure TForm1.FormDestroy(Sender: TObject);begin f.Free; f:= nil;end;
procedure TForm1.Button1Click(Sender: TObject);begin Memo1.Lines.Add( f.Find(Edit1.Text) );end;
{ TPhone }
function TPhone.Find(Const AStr7: String): String; //查找记录的地区信息 function GetArea(Idx:Int64):String; var Ansi: AnsiString; Buf: Byte; begin FStm.Position:= Idx; Buf:= 0; FStm.Read(Buf, 1); while (Buf <> 0) and (FStm.Position < FStm.Size) do begin Ansi := Ansi + AnsiChar(Buf) ; FStm.Read(Buf, 1); end; GetArea:= '地区信息:' + UTF8ToString(Ansi); end;type TRecord = Record Phone : Cardinal;//号码 Idx : Cardinal; //地址偏移 CardType: Byte; //卡类型 end;const FCount = 360569;var Phone: Integer;//手机号 L, R: Cardinal;//二叉树左右 Idx: Integer; //索引 Rec: TRecord;begin Result:= ''; Phone:= StrToInt(LeftStr(AStr7, 7));//手机号 case Phone of 1300000..1399999, 1500000..1599999, 1800000..1899999, 1450000..1459999, 1470000..1479999, 1700000..1709999, 1760000..1769999, 1770000..1779999:; else Result:= '你的手机号段在些库中尚未录入'; Exit; end;
L:= 0; R:= FCount; Idx:= (L+R) div 2; while Idx < FCount do begin FStm.Position:= FOffset + Idx * 9; FStm.Read(Rec, 9); if Rec.Phone = Phone then begin Result:= Result+ '手机前7位:'+IntToStr(Rec.Phone); case Rec.CardType of 1: Result:= Result+ #13#10'卡类型:移动'; 2: Result:= Result+ #13#10'卡类型:联通'; 3: Result:= Result+ #13#10'卡类型:电信'; 4: Result:= Result+ #13#10'卡类型:电信虚拟运营商'; 5: Result:= Result+ #13#10'卡类型:联通虚拟运营商'; 6: Result:= Result+ #13#10'卡类型:移动虚拟运营商'; end; Result:= Result+ #13#10 + GetArea(Rec.Idx); Exit; end else if Rec.Phone > Phone then begin R:= Idx; end else if Rec.Phone < Phone then begin L:= Idx; end; if L=R then begin Exit('未找到'); end; Idx:=(L+R) div 2; end;end;
procedure TPhone.LoadFromFile(const FileName: string);var Ansi: Array[0..3] of AnsiChar;begin FStm.LoadFromFile(FileName); FStm.Position:= 0; if FStm.Size > 0 then begin FStm.Read(Ansi, 4); FVersion:='版本号:'+ Ansi; FStm.Read(FOffset, 4); end;end;
constructor TPhone.Create();begin inherited; FStm:= TStringStream.Create;end;
destructor TPhone.Destroy;begin FStm.Free; FStm:= nil; inherited;end;
end. 来源:http://delphifmx.com/node/15
相关阅读 >>
Delphi winapi: getfocus - 获取当前拥有焦点的窗口的句柄
Delphi thread类的创建及使用(关于线程函数的传递例子)
更多相关阅读请进入《Delphi》频道 >>