📄 unttqqwry.pas
字号:
unit untTQQWry;
interface
uses
Windows, SysUtils, Classes, StrUtils, Controls, Math;
const //用于内存文件映射标志
QQWryMapFileTag = 'QQWryMapFile';
type
TQQWry = class(TObject)
public
constructor Create(AQQWryFileName: string);
destructor Destroy; override;
function GetQQWryFileName: string;
function GetQQWryFileSize: int64;
function GetIPDataNum: int64;
function GetQQWryDate: TDate;
function GetQQWryDataFrom: string;
procedure GetIPDataByIPRecordID(IPRecordID: int64; var IPData: PChar); overload;
procedure GetIPLocationByEndIPOffset(EndIPOffset: int64; var IPLocation: PChar);
procedure GetIPDataByIPRecordID(IPRecordID: int64; var IPData: TStringlist); overload;
function GetIPValue(IP: string): int64;
function GetIPDataID(IP: string): int64;
function ExtractIPDataToTxtFile(ATxtFileName: string): integer;
private
QQWryFileName: string;
QQWryFileSize: int64;
IPDataNum: int64;
FirstIPIndexOffset, LastIPIndexOffset: integer;
hQQWryFile, hQQWryMapFile: THandle;
pQQWryMapFile: Pointer;
pQQWryPos: PByte;
function GetFileSize(AFileName: string): int64;
end;
implementation
///**
//* 获取文件大小
//* @param (AFileName) (文件全名)
//* @return (文件大小)
//*/
function TQQWry.GetFileSize(AFileName: string): int64;
var
FileStream: TFileStream;
begin
try
FileStream:=TFileStream.Create(AFileName, fmOpenRead);
except
raise Exception.Create(format('文件 %s 无法打开!', [AFileName]));
exit;
end;
result:=FileStream.Size;
FileStream.Free;
end;
///**
//* 构造函数,构造一个TQQWry即纯真IP数据库处理对象
//* @param (AQQWryFileName) (纯真IP数据库文件的全文件名)
//* @return 无
//*/
constructor TQQWry.Create(AQQWryFileName: string);
var
Buffer: TOFStruct;
begin
inherited Create;
try
QQWryFileName:='QQWry.Dat';
//测文件存在
if not FileExists(QQWryFileName) then
raise Exception.Create(format('文件 %s 不存在!', [QQWryFileName]));
//测文件大小
QQWryFileSize:=GetFileSize(QQWryFileName);
if QQWryFileSize=0 then
raise Exception.Create(format('文件 %s 大小为空!', [QQWryFileName]));
//打开文件句柄
hQQWryFile:=OpenFile(PChar(QQWryFileName),
Buffer,
OF_READWRITE);
if hQQWryFile=-1 then
raise Exception.Create(format('文件 %s 不能打开!', [QQWryFileName]));
//创建文件映像对象
hQQWryMapFile:=CreateFileMapping(hQQWryFile,
nil,
PAGE_READWRITE,
0,
QQWryFileSize,
PChar(QQWryMapFileTag));
if hQQWryMapFile=0 then begin
CloseHandle(hQQWryFile);
raise Exception.Create('不能创建内存映象文件!');
end;
//获取映象文件映射地址
pQQWryMapFile:=MapViewOfFile(hQQWryMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if pQQWryMapFile=nil then begin
CloseHandle(hQQWryFile);
CloseHandle(hQQWryMapFile);
raise Exception.Create('不能获取文件映射地址!');
end;
pQQWryPos:=pQQWryMapFile;
FirstIPIndexOffset:=PInteger(pQQWryPos)^;
Inc(pQQWryPos, 4);
LastIPIndexOffset:=PInteger(pQQWryPos)^;
IPDataNum:=(LastIPIndexOffset - FirstIPIndexOffset) div 7 + 1;
except
on E: Exception do begin
raise Exception.Create(E.Message);
exit;
end;
end;
end;
///**
//* 析构函数 (释放TQQWry对象,关闭文件映射,关闭文件映像对象句柄,关闭文件句柄)
//* @param 无
//* @return 无
//*/
destructor TQQWry.Destroy;
begin
if pQQWryMapFile<>nil then UnMapViewOfFile(pQQWryMapFile); //关闭文件映射
if hQQWryMapFile<>0 then CloseHandle(hQQWryMapFile); //关闭文件映像对象句柄
if hQQWryFile<>0 then CloseHandle(hQQWryFile); //关闭文件句柄
inherited Destroy;
end;
///**
//* 获取纯真IP数据库文件的全文件名
//* @param 无
//* @return (纯真IP数据库文件的全文件名)
//*/
function TQQWry.GetQQWryFileName: string;
begin
Result:=QQWryFileName;
end;
///**
//* 获取纯真IP数据库文件大小
//* @param 无
//* @return (纯真IP数据库文件大小)
//*/
function TQQWry.GetQQWryFileSize: int64;
begin
Result:=QQWryFileSize;
end;
///**
//* 获取纯真IP数据库内含有的IP地址信息记录数
//* @param 无
//* @return (纯真IP数据库记录数)
//*/
function TQQWry.GetIPDataNum: int64;
begin
Result:=IPDataNum;
end;
///**
//* 获取当前QQIP数据库的更新日期
//* @param 无
//* @return QQIP当前数据库的更新日期 TDate
//*/
function TQQWry.GetQQWryDate: TDate;
var
DateString: string;
IPData: TStringlist;
begin
IPData:=TStringlist.Create;
GetIPDataByIPRecordID(GetIPDataNum, IPData);
DateString:=IPData[3];
IPData.Free;
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;
var
FromString: string;
IPData: TStringlist;
begin
IPData:=TStringlist.Create;
GetIPDataByIPRecordID(GetIPDataNum, IPData);
FromString:=IPData[2];
IPData.Free;
Result:=FromString;
end;
///**
//* 给定一个IP地址信息记录号,返回该项记录的信息
//* @param (IPRecordID, IPData) (IP地址信息记录号, 返回的该条信息:①起始IP 15字节 ②结束IP 15字节 ③国家 ④地区 ⑤回车键2字节)
//* @return 无
//*/
procedure TQQWry.GetIPDataByIPRecordID(IPRecordID: int64; var IPData: PChar);
var
EndIPOffset: integer;
i: integer;
pBlank, pReturn: PChar;
IPByteStr: string;
IPByteStrLen: integer;
IPDataPos: integer;
IPLocation: PChar;
begin
try
if (IPRecordID<=0) or (IPRecordID>GetIPDataNum) then
raise Exception.Create('IP信息记录号过小或越界!');
pBlank:=' ';
pReturn:=#13#10;
EndIPOffset:=0;
//取内存文件映射首地址
pQQWryPos:=pQQWryMapFile;
//根据记录的ID号移到该记录号的索引处,因为高位在后所以从后往前读
Inc(pQQWryPos, FirstIPIndexOffset + (IPRecordID - 1) * 7 + 3);
//取始末IP地址
//索引的前4个字节为该条记录的起始IP地址
IPDataPos:=0;
for i:=0 to 3 do begin
IPByteStr:=IntToStr(pQQWryPos^);
IPByteStrLen:=Length(IPByteStr);
CopyMemory(@IPData[IPDataPos], PChar(IPByteStr), IPByteStrLen);
Inc(IPDataPos, IPByteStrLen);
if i<>3 then begin
IPData[IPDataPos]:='.';
Inc(IPDataPos);
end;
dec(pQQWryPos);
end;
//填充空格至16位
CopyMemory(@IPData[IPDataPos], pBlank, 16-IPDataPos);
IPDataPos:=16;
Inc(pQQWryPos, 5);
//后3个字节是该条记录的内容区域的偏移值,内容区域的前4个字节为该条记录的结束IP地址
CopyMemory(@EndIPOffset, pQQWryPos, 3);
//取该条记录的结束IP地址
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, EndIPOffset + 3);
for i:=0 to 3 do begin
IPByteStr:=IntToStr(pQQWryPos^);
IPByteStrLen:=Length(IPByteStr);
CopyMemory(@IPData[IPDataPos], PChar(IPByteStr), IPByteStrLen);
Inc(IPDataPos, IPByteStrLen);
if i<>3 then begin
IPData[IPDataPos]:='.';
Inc(IPDataPos);
end;
dec(pQQWryPos);
end;
//填充空格至16位
CopyMemory(@IPData[IPDataPos], pBlank, 32-IPDataPos);
IPDataPos:=32;
//取该条记录的国家地区信息
IPLocation:=PChar(@IPData[IPDataPos]);
GetIPLocationByEndIPOffset(EndIPOffset, IPLocation);
//结尾的回车
if IPLocation[StrLen(IPLocation) - 1]<>' ' then
Inc(IPDataPos, StrLen(IPLocation))
else
Inc(IPDataPos, StrLen(IPLocation) - 1);
CopyMemory(@IPData[IPDataPos], pReturn, 2);
except
on E: Exception do begin
Destroy;
raise Exception.Create(E.Message);
exit;
end;
end;
end;
///**
//* 给定一条记录的结束IP地址的偏移,返回该条记录的国家地区信息
//* @param (EndIPOffset, IPLocation) (该条记录的结束IP地址偏移, 该条记录的国家地区信息)
//* @return 无
//*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -