解析步骤:
解析头部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