直接一个单元,代码分享出来。

 unit   Net.IPLocation;

 interface

 uses System.Classes, System.SysUtils, Winapi.WinSock, Vcl.Forms,
System.Math, System.SyncObjs; type
TIPLocation = class(TObject)
private
QQWryFileName: string;
QQWryFileStream: TBufferedFileStream;
QQWryFileSize: Cardinal;
IPRecordNum: Cardinal;
FirstIPIndexOffset, LastIPIndexOffset: Cardinal;
FLock: TCriticalSection; 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;
public
constructor Create(cQQWryFileName: string);
destructor Destroy; override;
function GetLocation(IP: string): String;
end; function IPLocation: TIPLocation; implementation var
__IPLocation: TIPLocation; function IPLocation: TIPLocation;
begin
if __IPLocation = nil then
__IPLocation := TIPLocation.Create(ExtractFilePath(ParamStr()) +
'qqwry.dat'); Result := __IPLocation;
end; { TIPLocation } constructor TIPLocation.Create(cQQWryFileName: string);
begin
inherited Create;
FLock := TCriticalSection.Create;
QQWryFileName := cQQWryFileName;
QQWryFileStream := TBufferedFileStream.Create(QQWryFileName,
fmOpenRead or fmShareDenyWrite, );
QQWryFileSize := QQWryFileStream.Size;
QQWryFileStream.Read(FirstIPIndexOffset, );
QQWryFileStream.Read(LastIPIndexOffset, );
IPRecordNum := (LastIPIndexOffset - FirstIPIndexOffset) div + ;
end; destructor TIPLocation.Destroy;
begin QQWryFileStream.Free;
FLock.Free;
inherited Destroy;
end; function TIPLocation.GetIPLocation(IPLocationOffset: Cardinal): TStringlist;
const
// 实际信息字串存放位置的重定向模式
REDIRECT_MODE_ = ;
REDIRECT_MODE_ = ;
var
RedirectMode: byte;
CountryFirstOffset, CountrySecondOffset: Cardinal;
CountryMsg, AreaMsg: string;
//
function ReadString(StringOffset: Cardinal): ansistring;
var
ReadByte: ansichar;
begin
Result := '';
QQWryFileStream.Seek(StringOffset, soFromBeginning);
QQWryFileStream.Read(ReadByte, );
while ord(ReadByte) <> do
begin
Result := Result + ReadByte;
QQWryFileStream.Read(ReadByte, );
end;
end;
//
function ReadArea(AreaOffset: Cardinal): ansistring;
var
ModeByte: byte;
ReadAreaOffset: Cardinal;
begin
ReadAreaOffset := ;
QQWryFileStream.Seek(AreaOffset, soFromBeginning);
QQWryFileStream.Read(ModeByte, );
if (ModeByte = REDIRECT_MODE_) or (ModeByte = REDIRECT_MODE_) then
begin
QQWryFileStream.Read(ReadAreaOffset, );
if ReadAreaOffset = then
Result := '未知地区'
else
Result := ReadString(ReadAreaOffset);
end
else
begin
Result := ReadString(AreaOffset);
end;
end; begin
CountryFirstOffset := ;
CountrySecondOffset := ;
// 跳过4个字节,该4字节内容为该条IP信息里IP地址段中的终止IP值
QQWryFileStream.Seek(IPLocationOffset + , soFromBeginning);
// 读取国家信息的重定向模式值
QQWryFileStream.Read(RedirectMode, );
// 重定向模式1的处理
if RedirectMode = REDIRECT_MODE_ then
begin
// 模式值为1,则后3个字节的内容为国家信息的重定向偏移值
QQWryFileStream.ReadData(CountryFirstOffset, );
// 进行重定向
QQWryFileStream.Seek(CountryFirstOffset, soFromBeginning);
// 第二次读取国家信息的重定向模式
QQWryFileStream.Read(RedirectMode, );
// 第二次重定向模式为模式2的处理
if RedirectMode = REDIRECT_MODE_ then
begin
// 后3字节的内容即为第二次重定向偏移值
QQWryFileStream.ReadData(CountrySecondOffset, );
// 读取第二次重定向偏移值下的字符串值,即为国家信息
CountryMsg := ReadString(CountrySecondOffset);
// 若第一次重定向模式为1,进行重定向后读取的第二次重定向模式为2,
// 则地区信息存放在第一次国家信息偏移值的后面
QQWryFileStream.Seek(CountryFirstOffset + , soFromBeginning);
// 第二次重定向模式不是模式2的处理
end
else
begin
CountryMsg := ReadString(CountryFirstOffset);
end;
// 在重定向模式1下读地区信息值
AreaMsg := ReadArea(QQWryFileStream.Position);
// 重定向模式2的处理
end
else if RedirectMode = REDIRECT_MODE_ then
begin
QQWryFileStream.ReadData(CountrySecondOffset, );
CountryMsg := ReadString(CountrySecondOffset);
AreaMsg := ReadArea(IPLocationOffset + );
// 不是重定向模式的处理,存放的即是IP地址信息
end
else
begin
CountryMsg := ReadString(QQWryFileStream.Position - );
AreaMsg := ReadArea(QQWryFileStream.Position);
end;
Result := TStringlist.Create;
Result.Add(CountryMsg);
Result.Add(AreaMsg);
end; function TIPLocation.GetIPMsg(IPRecordID: Cardinal): TStringlist;
var
aryStartIP: array [ .. ] of byte;
strStartIP: string;
EndIPOffset: Cardinal;
aryEndIP: array [ .. ] of byte;
strEndIP: string;
i: integer;
begin
EndIPOffset := ; // 根据记录ID号移到该记录号的索引处
QQWryFileStream.Seek(FirstIPIndexOffset + (IPRecordID - ) * ,
soFromBeginning);
// 索引的前4个字节为起始IP地址
QQWryFileStream.Read(aryStartIP, );
// 后3个字节是内容区域的偏移值
// QQWryFileStream.Read(EndIPOffset, 3);
QQWryFileStream.ReadData(EndIPOffset, );
// 移至内容区域
QQWryFileStream.Seek(EndIPOffset, soFromBeginning);
// 内容区域的前4个字节为终止IP地址
QQWryFileStream.Read(aryEndIP, ); // 将起止IP地址转换为点分的形式
strStartIP := '';
for i := downto do
begin
if i <> then
strStartIP := strStartIP + IntToStr(aryStartIP[i]) + '.'
else
strStartIP := strStartIP + IntToStr(aryStartIP[i]);
end;
strEndIP := '';
for i := downto do
begin
if i <> 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; function TIPLocation.GetIPRecordID(IP: string): Cardinal;
function SearchIPRecordID(IPRecordFrom, IPRecordTo, IPValue: Cardinal)
: Cardinal;
var
CompareIPValue1, CompareIPValue2: Cardinal;
begin
Result := ;
CompareIPValue1 := ;
CompareIPValue2 := ;
QQWryFileStream.Seek(FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div
+ IPRecordFrom - ) * , soFromBeginning);
QQWryFileStream.Read(CompareIPValue1, );
QQWryFileStream.Seek(FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div
+ IPRecordFrom) * , soFromBeginning);
QQWryFileStream.Read(CompareIPValue2, );
// 找到了
if (IPValue >= CompareIPValue1) and (IPValue < CompareIPValue2) then
begin
Result := (IPRecordTo - IPRecordFrom) div + IPRecordFrom;
end
else
// 后半段找
if IPValue > CompareIPValue1 then
begin
Result := SearchIPRecordID((IPRecordTo - IPRecordFrom) div +
IPRecordFrom + , IPRecordTo, IPValue);
end
else
// 前半段找
if IPValue < CompareIPValue1 then
begin
Result := SearchIPRecordID(IPRecordFrom, (IPRecordTo - IPRecordFrom)
div + IPRecordFrom - , IPValue);
end;
end; begin
Result := SearchIPRecordID(, GetIPRecordNum, GetIPValue(IP));
end; function TIPLocation.GetIPRecordNum: Cardinal;
begin
Result := IPRecordNum;
end; function TIPLocation.GetIPValue(IP: string): Cardinal;
var
tsIP: TStringlist;
i: integer;
function SplitStringToStringlist(aString: string; aSplitChar: string)
: TStringlist;
begin
Result := TStringlist.Create;
while pos(aSplitChar, aString) > do
begin
Result.Add(copy(aString, , pos(aSplitChar, aString) - ));
aString := copy(aString, pos(aSplitChar, aString) + ,
length(aString) - pos(aSplitChar, aString));
end;
Result.Add(aString);
end; begin
tsIP := SplitStringToStringlist(IP, '.');
Result := ;
for i := downto do
begin
Result := Result + StrToInt(tsIP[i]) * trunc(power(, - i));
end;
end; function TIPLocation.GetLocation(IP: string): String;
begin
FLock.Enter;
try
Result := GetIPMsg(GetIPRecordID(IP))[];
finally
FLock.Leave;
end;
end; function TIPLocation.GetQQWryDataFrom: string;
begin
Result := GetIPMsg(GetIPRecordNum)[];
end; function TIPLocation.GetQQWryDate: TDate;
var
DateString: string;
begin
DateString := GetIPMsg(GetIPRecordNum)[];
DateString := copy(DateString, , pos('IP数据', DateString) - );
DateString := StringReplace(DateString, '年', '-',
[rfReplaceAll, rfIgnoreCase]);
DateString := StringReplace(DateString, '月', '-',
[rfReplaceAll, rfIgnoreCase]);
DateString := StringReplace(DateString, '日', '-',
[rfReplaceAll, rfIgnoreCase]);
Result := StrToDate(DateString);
end; function TIPLocation.GetQQWryFileName: string;
begin
Result := QQWryFileName;
end; function TIPLocation.GetQQWryFileSize: Cardinal;
begin
Result := QQWryFileSize;
end; initialization finalization if __IPLocation <> nil then
__IPLocation.Free; end.

纯真IP数据库解析Delphi D10.1下正常使用的更多相关文章

  1. python3通过纯真IP数据库查询IP归属地信息

    在网上看到的别人写的python2的代码,修改成了python3. 把纯真IP数据库文件qqwry.dat放到czip.py同一目录下. #! /usr/bin/env python # -*- co ...

  2. 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)

    纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat) 转载自:http://blog.cafeboy.org/2011/02/25/qqwry-to-ipwry/ ht ...

  3. PHP利用纯真IP数据库在本地实现IP地址信息查询

    https://blog.csdn.net/myweishanli/article/details/45098693 准备工作: 建议本地IP地址数据库,请到http://www.cz88.net/这 ...

  4. PHP调用纯真IP数据库返回具体地址

    function convertip($ip) { $ip1num = 0; $ip2num = 0; $ipAddr1 =""; $ipAddr2 =""; ...

  5. 纯真IP数据库导入mysql

    下载纯真IP数据库 安装后解压到本地为ip.txt 格式为: 1.1.145.0       1.1.147.255     泰国 沙功那空 1.1.148.0       1.1.149.255   ...

  6. 优化读取纯真IP数据库QQWry.dat获取地区信息

    改自HeDaode 2007-12-28的代码 将之改为从硬盘读取后文件后,将MemoryStream放到内存中,提高后续查询速度 ///<summary> /// 提供从纯真IP数据库搜 ...

  7. PHP获取IP及地区信息(纯真IP数据库)

    昨天在写程序的时候,发现在用户的时候记录IP和地区信息也许以后用得上,去网上找了找,发现实现的方式有好多好多,因为我用的ThinkPHP,后来又去TP官网找了找,最后采用了下面这种方法. <?p ...

  8. 纯真IP数据库格式详解

    纯真版IP数据库,优点是记录多,查询速度快,它只用一个文件QQWry.dat就包含了所有记录,方便嵌入到其他程序中,也方便升级.缺点是你想要编辑它却是比较麻烦的,由于其文件格式的限制,你要直接添加IP ...

  9. 纯真IP数据库格式详解 附demo

    纯真版IP数据库,优点是记录多,查询速度快,它只用一个文件QQWry.dat就包含了所有记录,方便嵌入到其他程序中,也方便升级.缺点是你想要编辑它却是比较麻烦的,由于其文件格式的限制,你要直接添加IP ...

随机推荐

  1. julia应用于自动驾驶汽车、机器人、3D 打印、精准医疗、增强现实、基因组学、能源交易、机器学习、金融风控和太空任务设计等多个领域

    编程界的新宠 Julia 发布 1.0 正式版本,多种优势集于一身2018-08-14 14:14 公司Julia 的累积下载次数超过 200 万,已被应用于自动驾驶汽车.机器人.3D 打印.精准医疗 ...

  2. Mybatis数据库操作的返回值

    mybatis配置 <!-- 配置mybatis --> <bean id="sqlSessionFactory" class="org.mybatis ...

  3. TCP三次握手连接和TCP四次挥手及大量TIME_WAIT解决方法:

    1.TCP建立连接,三次握手 建立的TCP连接可靠的连接,必须经过三次握手建立连接才能正式通信彼此传输数数据. 客户端请求服务端建立连接 第一次握手:客户给服务发送一个请求报文SYN, 客户端的状态置 ...

  4. SqlMap之数据库操作语句总结

    SQLMAP是一款开源的渗透测试程序,它可以自动探测和利用SQL注入漏洞来获得我们想要的数据.我们可以利用它执行特定的命令.查看文件.获取各种数据:当然,最猥琐的是它利用注入点拖库的速率还是灰常让人满 ...

  5. 【android开发】10款实用的Android UI工具,非常有用!

    移动应用的UI设计就好似达摩克利斯之剑,一方面,一个视觉.交互.体验良好的UI可以加强应用在用户心目中的形象和识别性.而另一方面,一个体验糟糕的UI设计不仅无法让用户沉浸在应用中,还会造成用户对应用产 ...

  6. 程序的入口及AppDelegate窗体显示原理

    AppDelegate.m - (void)dealloc { [_window release]; [super dealloc]; } - (BOOL)application:(UIApplica ...

  7. redis学习笔记——RDB和AOF持久化一

    为防止数据丢失,需要将 Redis 中的数据从内存中 dump 到磁盘,这就是持久化.Redis 提供两种持久化方式:RDB 和 AOF.Redis 允许两者结合,也允许两者同时关闭. RDB 可以定 ...

  8. java中==与equal()的区别

    ==和equal()都是用来判断两个变量是否相等的. (1)如果两个变量是基本类型变量,且都是数值型的(不一定数据类型相同),只要是值相同,将返回true; (2)如果两个变量是引用型变量,只有它们指 ...

  9. JS动画公式

    // 效果: // Linear:无缓动效果 // Quadratic:二次方的缓动(t^2) // Cubic:三次方的缓动(t^3) // Quartic:四次方的缓动(t^4) // Quint ...

  10. 【Firefly API文档】—— Package Distributed

    http://bbs.gameres.com/forum.php?mod=viewthread&tid=219654 package distributed 这个包中主要封装了各个服务进程间进 ...