unit MyIp;interfaceuses
SysUtils, Classes, Controls, Math, Dialogs;type
TQQWry = class(TObject)
public
constructor Create(cQQWryFileName: string);
destructor Destroy; override;
function GetQQWryFileName: string;
function GetQQWryFileSize: Cardinal;
function GetIPRecordNum: Cardinal;
function GetQQWryDate: TDate;
function GetQQWryDataFrom: string;
function GetIPLocation(IPLocationOffset: Cardinal): TStringlist;
function GetIPMsg(IPRecordID: Cardinal): TStringlist;
function GetIPRecordID(IP: string): Cardinal;
function GetIPValue(IP: string): Cardinal;
private
QQWryFileName: string;
QQWryFileStream: TFileStream;
QQWryFileSize: Cardinal;
IPRecordNum: Cardinal;
FirstIPIndexOffset, LastIPIndexOffset: Cardinal;
end;implementation///**
//* 构造一个TQQWry即QQIP地址数据库的对象
//* @param cQQWryFileName QQIP数据库文件的全名(包括路径),请确认文件存在和可读性
//* @return 无
//*/
constructor TQQWry.Create(cQQWryFileName: string);
begin
inherited Create;
QQWryFileName:=cQQWryFileName;
QQWryFileStream:=TFileStream.Create(QQWryFileName, fmOpenRead or fmShareDenyWrite, 0);
QQWryFileSize:=QQWryFileStream.Size;
QQWryFileStream.Read(FirstIPIndexOffset, 4);
QQWryFileStream.Read(LastIPIndexOffset, 4);
IPRecordNum:=(LastIPIndexOffset - FirstIPIndexOffset) div 7 + 1;
end;///**
//* 析构函数,释放TQQWry对象,释放文件数据流对象
//* @param 无
//* @return 无
//*/
destructor TQQWry.Destroy;
begin
QQWryFileStream.Free;
inherited Destroy;
end;///**
//* 获取QQIP数据库文件的全名(包括路径)
//* @param 无
//* @return QQIP数据库文件的全名(包括路径) string
//*/
function TQQWry.GetQQWryFileName: string;
begin
Result:=QQWryFileName;
end;///**
//* 获取QQIP数据库文件大小
//* @param 无
//* @return QQIP数据库文件大小 Cardinal
//*/
function TQQWry.GetQQWryFileSize: Cardinal;
begin
Result:=QQWryFileSize;
end;///**
//* 获取QQIP数据库内含有的IP地址信息记录条数
//* @param 无
//* @return QQIP数据库文件大小 Cardinal
//*/
function TQQWry.GetIPRecordNum: Cardinal;
begin
Result:=IPRecordNum;
end;///**
//* 获取当前QQIP数据库的更新日期
//* @param 无
//* @return QQIP当前数据库的更新日期 TDate
//*/
function TQQWry.GetQQWryDate: TDate;
var
DateString: string;
begin
DateString:=GetIPMsg(GetIPRecordNum)[3];
DateString:=copy(DateString, 1, pos('IP数据', DateString) - 1);
DateString:=StringReplace(DateString, '年', '-', [rfReplaceAll, rfIgnoreCase]);
DateString:=StringReplace(DateString, '月', '-', [rfReplaceAll, rfIgnoreCase]);
DateString:=StringReplace(DateString, '日', '-', [rfReplaceAll, rfIgnoreCase]);
Result:=StrToDate(DateString);
end;///**
//* 获取当前QQIP数据库的来源信息
//* @param 无
//* @return 当前QQIP数据库的来源信息 string
//*/
function TQQWry.GetQQWryDataFrom: string;
begin
Result:=GetIPMsg(GetIPRecordNum)[2];
end;///**
//* 给定一个IP国家地区记录的偏移,返回该IP地址的信息
//* @param IPLocationOffset 国家记录的偏移 Cardinal
//* @return IP地址信息(国家信息/地区信息) string
//*/
function TQQWry.GetIPLocation(IPLocationOffset: Cardinal): TStringlist;
const
//实际信息字串存放位置的重定向模式
REDIRECT_MODE_1 = 1;
REDIRECT_MODE_2 = 2;
var
RedirectMode: byte;
CountryFirstOffset, CountrySecondOffset: Cardinal;
CountryMsg, AreaMsg: string;
///**
//* 给定一个文件偏移值,返回在数据文件中该偏移下的字符串,即读取到0结尾的字符前
//* @param StringOffset 字符串在文件中的偏移值 Cardinal
//* @return 字符串 string
//*/
function ReadString(StringOffset: Cardinal): string;
var
ReadByte: char;
begin
Result:='';
QQWryFileStream.Seek(StringOffset, soFromBeginning);
QQWryFileStream.Read(ReadByte, 1);
while ord(ReadByte)<>0 do begin
Result := Result + ReadByte;
QQWryFileStream.Read(ReadByte, 1);
end;
end;
///**
//* 给定一个地区信息偏移值,返回在数据文件中该偏移量下的地区信息
//* @param AreaOffset 地区信息在文件中的偏移值 Cardinal;
//* @return 地区信息字符串 string
//*/
function ReadArea(AreaOffset: Cardinal): string;
var
ModeByte: byte;
ReadAreaOffset: Cardinal;
begin
QQWryFileStream.Seek(AreaOffset, soFromBeginning);
QQWryFileStream.Read(ModeByte, 1);
if (ModeByte = REDIRECT_MODE_1) or (ModeByte = REDIRECT_MODE_2) then begin
QQWryFileStream.Read(ReadAreaOffset, 3);
if ReadAreaOffset=0 then Result:='未知地区'
else Result:=ReadString(ReadAreaOffset);
end else begin
Result:=ReadString(AreaOffset);
end;
end;
begin
//跳过4个字节,该4字节内容为该条IP信息里IP地址段中的终止IP值
QQWryFileStream.Seek(IPLocationOffset + 4, soFromBeginning);
//读取国家信息的重定向模式值
QQWryFileStream.Read(RedirectMode, 1); //重定向模式1的处理
if RedirectMode = REDIRECT_MODE_1 then begin
//模式值为1,则后3个字节的内容为国家信息的重定向偏移值
QQWryFileStream.Read(CountryFirstOffset, 3);
//进行重定向
QQWryFileStream.Seek(CountryFirstOffset, soFromBeginning);
//第二次读取国家信息的重定向模式
QQWryFileStream.Read(RedirectMode, 1);
//第二次重定向模式为模式2的处理
if RedirectMode = REDIRECT_MODE_2 then begin
//后3字节的内容即为第二次重定向偏移值
QQWryFileStream.Read(CountrySecondOffset, 3);
//读取第二次重定向偏移值下的字符串值,即为国家信息
CountryMsg:=ReadString(CountrySecondOffset);
//若第一次重定向模式为1,进行重定向后读取的第二次重定向模式为2,
//则地区信息存放在第一次国家信息偏移值的后面
QQWryFileStream.Seek(CountryFirstOffset + 4, soFromBeginning);
//第二次重定向模式不是模式2的处理
end else begin
CountryMsg:=ReadString(CountryFirstOffset);
end;
//在重定向模式1下读地区信息值
AreaMsg:=ReadArea(QQWryFileStream.Position);
//重定向模式2的处理
end else if RedirectMode = REDIRECT_MODE_2 then begin
QQWryFileStream.Read(CountrySecondOffset, 3);
CountryMsg:=ReadString(CountrySecondOffset);
AreaMsg:=ReadArea(IPLocationOffset + 8);
//不是重定向模式的处理,存放的即是IP地址信息
end else begin
CountryMsg:=ReadString(QQWryFileStream.Position - 1);
AreaMsg:=ReadArea(QQWryFileStream.Position);
end;
Result:=TStringlist.Create;
Result.Add(CountryMsg);
Result.Add(AreaMsg);
end;///**
//* 给定一个IP地址信息记录号,返回该项记录的信息
//* @param IPRecordID IP地址信息记录号 Cardinal
//* @return 记录号信息(含3个部分:①起始IP地址 ②终止IP地址 ③国家信息/地区信息) TStringlist
//*/
function TQQWry.GetIPMsg(IPRecordID: Cardinal): TStringlist;
var
aryStartIP: array[1..4] of byte;
strStartIP: string; EndIPOffset: Cardinal;
aryEndIP: array[1..4] of byte;
strEndIP: string; i: integer;
begin
//根据记录ID号移到该记录号的索引处
QQWryFileStream.Seek(FirstIPIndexOffset + (IPRecordID - 1) * 7, soFromBeginning);
//索引的前4个字节为起始IP地址
QQWryFileStream.Read(aryStartIP, 4);
//后3个字节是内容区域的偏移值
QQWryFileStream.Read(EndIPOffset, 3); //移至内容区域
QQWryFileStream.Seek(EndIPOffset, soFromBeginning);
//内容区域的前4个字节为终止IP地址
QQWryFileStream.Read(aryEndIP, 4); //将起止IP地址转换为点分的形式
strStartIP:='';
for i:=4 downto 1 do begin
if i<>1 then strStartIP:=strStartIP + IntToStr(aryStartIP[i]) + '.'
else strStartIP:=strStartIP + IntToStr(aryStartIP[i]);
end; strEndIP:='';
for i:=4 downto 1 do begin
if i<>1 then strEndIP:=strEndIP + IntToStr(aryEndIP[i]) + '.'
else strEndIP:=strEndIP + IntToStr(aryEndIP[i]);
end; Result:=TStringlist.Create;
Result.Add(strStartIP);
Result.Add(strEndIP);
//获取该条记录下的IP地址信息
//以下三者是统一的:①内容区域的偏移值 ②终止IP地址的存放位置 ③国家信息紧接在终止IP地址存放位置后
Result.AddStrings(GetIPLocation(EndIPOffset));
end;///**
//* 给定一个IP地址(四段点分字符串形式),返回该IP的数值
//* @param IP IP地址(四段点分字符串形式) string
//* @return 该IP的数值 Cardinal
//*/
function TQQWry.GetIPValue(IP: string): Cardinal;
var
tsIP: TStringlist;
i: integer;
function SplitStringToStringlist(aString: string; aSplitChar: string): TStringlist;
begin
Result:=TStringList.Create;
while pos(aSplitChar, aString)>0 do begin
Result.Add(copy(aString, 1, pos(aSplitChar, aString)-1));
aString:=copy(aString, pos(aSplitChar, aString)+1, length(aString)-pos(aSplitChar, aString));
end;
Result.Add(aString);
end;
begin
tsIP:=SplitStringToStringlist(IP, '.');
Result:=0;
for i:=3 downto 0 do begin
Result:=Result + StrToInt(tsIP[i]) * trunc(power(256, 3-i));
end;
end;///**
//* 给定一个IP地址(四段点分字符串形式),返回该IP地址所在的记录号
//* @param IP IP地址(四段点分字符串形式) string
//* @return 该IP地址所在的记录号 Cardinal
//*/
function TQQWry.GetIPRecordID(IP: string): Cardinal;
function SearchIPRecordID(IPRecordFrom, IPRecordTo, IPValue: Cardinal): Cardinal;
var
CompareIPValue1, CompareIPValue2: Cardinal;
begin
Result:=0;
QQWryFileStream.Seek(FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom - 1) * 7, soFromBeginning);
QQWryFileStream.Read(CompareIPValue1, 4);
QQWryFileStream.Seek(FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom) * 7, soFromBeginning);
QQWryFileStream.Read(CompareIPValue2, 4);
//找到了
if (IPValue>=CompareIPValue1) and (IPValue<CompareIPValue2) then begin
Result:=(IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom;
end else
//后半段找
if IPValue>CompareIPValue1 then begin
Result:=SearchIPRecordID((IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom + 1, IPRecordTo, IPValue);
end else
//前半段找
if IPValue<CompareIPValue1 then begin
Result:=SearchIPRecordID(IPRecordFrom, (IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom - 1, IPValue);
end;
end;
begin
Result:=SearchIPRecordID(1, GetIPRecordNum, GetIPValue(IP));
end;end.QQWryStr:=PChar(ExtractFilePath(Application.Exename))+'QQWry.Dat';
QQWry:=TQQWry.Create(QQWryStr);
item.subitems.add(QQWry.GetIPMsg(QQWry.GetIPRecordID(Port.Strings[0]))[2]); //地理位置
QQWry.Free;
解决方案 »
- adoquery.append;
- 想利用假期翻译数据库建模利器powerdesigner9.5的英文资料,造福E文不好的朋友,有人支持吗??
- 如何使Delphi7编出可在未安装Delphi机器上运行的执行文件啊
- 怎么调试service的程序?
- delphi5,delphi6,delphi7有什么差别,哪个最好,哪个最经典?
- 十万火急,delphi,sqlserver数据库开发。
- treeview怎样标识某个结点(象vb中treeview结点的主键)?接昨天的问题
- delphi编译的32位Dll怎么转成64位Dll(有源码)
- 如何制作DBGrid复杂表头
- DELPHI如何发布
- delphi indy TIdPeerThread 编译提示未定义
- string的迷惑,感觉很奇怪的1个问题
function ReadString(StringOffset: Cardinal): string;
function ReadArea(AreaOffset: Cardinal): string;
试试改成Ansistring.另外你的对象 看上去是个对象, 但是是一个杂乱的气泡类. 先好好看看别人是如何封装对象的, 不然会继续错下去, 到最后根本养成不了面向对象的思维.