C#读取QQ纯真IP数据库QQWry.Dat的代码

QQ纯真IP库算是IP地址收集较为全的一个IP库,对于IP查询来说这个是不错的选择。下面是如何查询纯真IP库的一个类,使用C#代码。
纯真版QQ IP数据库 
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.IO; 
using System.Web; 
using System.Configuration; 

namespace BLL 

public class IPLocationSearch 

private static readonly QQWry qq = new QQWry(ConfigurationManager.AppSettings["ip"] + "qqwry.dat"); 

public static IPLocation GetIPLocation(string ip) 

return qq.SearchIPLocation(ip); 



/* 
使用方法: 

例子: 
BDQQ.Data.QQWry qq=new BDQQ.Data.QQWry("d:\\QQWry.Dat"); 
BDQQ.Data.IPLocation ip=qq.SearchIPLocation("127.0.0.1");//这里添写IP地址 
Console.WriteLine(ip.country);//国家 
Console.WriteLine(ip.area);//地区 
*/ 

//以下是类文件 
//根据LumaQQ改写而成. 

/**/ 
///<summary> 
/// QQWry 的摘要说明。 
///</summary> 
public class QQWry 

//第一种模式 
#region 第一种模式 
/**/ 
///<summary> 
///第一种模式 
///</summary> 
#endregion 
private const byte REDIRECT_MODE_1 = 0x01; 

//第二种模式 
#region 第二种模式 
/**/ 
///<summary> 
///第二种模式 
///</summary> 
#endregion 
private const byte REDIRECT_MODE_2 = 0x02; 

//每条记录长度 
#region 每条记录长度 
/**/ 
///<summary> 
///每条记录长度 
///</summary> 
#endregion 
private const int IP_RECORD_LENGTH = 7; 

//数据库文件 
#region 数据库文件 
/**/ 
///<summary> 
///文件对象 
///</summary> 
#endregion 
private FileStream ipFile; 

private const string unCountry = "未知国家"; 
private const string unArea = "未知地区"; 

//索引开始位置 
#region 索引开始位置 
/**/ 
///<summary> 
///索引开始位置 
///</summary> 
#endregion 
private long ipBegin; 

//索引结束位置 
#region 索引结束位置 
/**/ 
///<summary> 
///索引结束位置 
///</summary> 
#endregion 
private long ipEnd; 

//IP地址对象 
#region IP地址对象 
/**/ 
///<summary> 
/// IP对象 
///</summary> 
#endregion 
private IPLocation loc; 

//存储文本内容 
#region 存储文本内容 
/**/ 
///<summary> 
///存储文本内容 
///</summary> 
#endregion 
private byte[] buf; 

//存储3字节 
#region 存储3字节 
/**/ 
///<summary> 
///存储3字节 
///</summary> 
#endregion 
private byte[] b3; 

//存储4字节 
#region 存储4字节 
/**/ 
///<summary> 
///存储4字节IP地址 
///</summary> 
#endregion 
private byte[] b4; 

//构造函数 
#region 构造函数 
/**/ 
///<summary> 
///构造函数 
///</summary> 
///<param name="ipfile">IP数据库文件绝对路径</param> 
#endregion 
public QQWry(string ipfile) 


buf = new byte[100]; 
b3 = new byte[3]; 
b4 = new byte[4]; 
try 

ipFile = new FileStream(ipfile, FileMode.Open); 

catch (Exception ex) 

throw new Exception(ex.Message); 

ipBegin = readLong4(0); 
ipEnd = readLong4(4); 
loc = new IPLocation(); 


//根据IP地址搜索 
#region 根据IP地址搜索 
/**/ 
///<summary> 
///搜索IP地址搜索 
///</summary> 
///<param name="ip"></param> 
///<returns></returns> 
#endregion 
public IPLocation SearchIPLocation(string ip) 

//将字符IP转换为字节 
string[] ipSp = ip.Split('.'); 
if (ipSp.Length != 4) 

throw new ArgumentOutOfRangeException("不是合法的IP地址!"); 

byte[] IP = new byte[4]; 
for (int i = 0; i < IP.Length; i++) 

IP[i] = (byte)(Int32.Parse(ipSp[i]) & 0xFF); 


IPLocation local = null; 
long offset = locateIP(IP); 

if (offset != -1) 

local = getIPLocation(offset); 


if (local == null) 

local = new IPLocation(); 
local.area = unArea; 
local.country = unCountry; 

return local; 


//取得具体信息 
#region 取得具体信息 
/**/ 
///<summary> 
///取得具体信息 
///</summary> 
///<param name="offset"></param> 
///<returns></returns> 
#endregion 
private IPLocation getIPLocation(long offset) 

ipFile.Position = offset + 4; 
//读取第一个字节判断是否是标志字节 
byte one = (byte)ipFile.ReadByte(); 
if (one == REDIRECT_MODE_1) 

//第一种模式 
//读取国家偏移 
long countryOffset = readLong3(); 
//转至偏移处 
ipFile.Position = countryOffset; 
//再次检查标志字节 
byte b = (byte)ipFile.ReadByte(); 
if (b == REDIRECT_MODE_2) 

loc.country = readString(readLong3()); 
ipFile.Position = countryOffset + 4; 

else 
loc.country = readString(countryOffset); 

//读取地区标志 
loc.area = readArea(ipFile.Position); 


else if (one == REDIRECT_MODE_2) 

//第二种模式 
loc.country = readString(readLong3()); 
loc.area = readArea(offset + 8); 

else 

//普通模式 
loc.country = readString(--ipFile.Position); 
loc.area = readString(ipFile.Position); 

return loc; 


//取得地区信息 
#region 取得地区信息 
/**/ 
///<summary> 
///读取地区名称 
///</summary> 
///<param name="offset"></param> 
///<returns></returns> 
#endregion 
private string readArea(long offset) 

ipFile.Position = offset; 
byte one = (byte)ipFile.ReadByte(); 
if (one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2) 

long areaOffset = readLong3(offset + 1); 
if (areaOffset == 0) 
return unArea; 
else 

return readString(areaOffset); 


else 

return readString(offset); 



//读取字符串 
#region 读取字符串 
/**/ 
///<summary> 
///读取字符串 
///</summary> 
///<param name="offset"></param> 
///<returns></returns> 
#endregion 
private string readString(long offset) 

ipFile.Position = offset; 
int i = 0; 
for (i = 0, buf[i] = (byte)ipFile.ReadByte(); buf[i] != (byte)(0); buf[++i] = (byte)ipFile.ReadByte()) ; 

if (i > 0) 
return Encoding.Default.GetString(buf, 0, i); 
else 
return ""; 


//查找IP地址所在的绝对偏移量 
#region 查找IP地址所在的绝对偏移量 
/**/ 
///<summary> 
///查找IP地址所在的绝对偏移量 
///</summary> 
///<param name="ip"></param> 
///<returns></returns> 
#endregion 
private long locateIP(byte[] ip) 

long m = 0; 
int r; 

//比较第一个IP项 
readIP(ipBegin, b4); 
r = compareIP(ip, b4); 
if (r == 0) 
return ipBegin; 
else if (r < 0) 
return -1; 
//开始二分搜索 
for (long i = ipBegin, j = ipEnd; i < j; ) 

m = this.getMiddleOffset(i, j); 
readIP(m, b4); 
r = compareIP(ip, b4); 
if (r > 0) 
i = m; 
else if (r < 0) 

if (m == j) 

j -= IP_RECORD_LENGTH; 
m = j; 

else 

j = m; 


else 
return readLong3(m + 4); 

m = readLong3(m + 4); 
readIP(m, b4); 
r = compareIP(ip, b4); 
if (r <= 0) 
return m; 
else 
return -1; 


//读出4字节的IP地址 
#region 读出4字节的IP地址 
/**/ 
///<summary> 
///从当前位置读取四字节,此四字节是IP地址 
///</summary> 
///<param name="offset"></param> 
///<param name="ip"></param> 
#endregion 
private void readIP(long offset, byte[] ip) 

ipFile.Position = offset; 
ipFile.Read(ip, 0, ip.Length); 
byte tmp = ip[0]; 
ip[0] = ip[3]; 
ip[3] = tmp; 
tmp = ip[1]; 
ip[1] = ip[2]; 
ip[2] = tmp; 


//比较IP地址是否相同 
#region 比较IP地址是否相同 
/**/ 
///<summary> 
///比较IP地址是否相同 
///</summary> 
///<param name="ip"></param> 
///<param name="beginIP"></param> 
///<returns>0:相等,1:ip大于beginIP,-1:小于</returns> 
#endregion 
private int compareIP(byte[] ip, byte[] beginIP) 

for (int i = 0; i < 4; i++) 

int r = compareByte(ip[i], beginIP[i]); 
if (r != 0) 
return r; 

return 0; 


//比较两个字节是否相等 
#region 比较两个字节是否相等 
/**/ 
///<summary> 
///比较两个字节是否相等 
///</summary> 
///<param name="bsrc"></param> 
///<param name="bdst"></param> 
///<returns></returns> 
#endregion 
private int compareByte(byte bsrc, byte bdst) 

if ((bsrc & 0xFF) > (bdst & 0xFF)) 
return 1; 
else if ((bsrc ^ bdst) == 0) 
return 0; 
else 
return -1; 


//根据当前位置读取4字节 
#region 根据当前位置读取4字节 
/**/ 
///<summary> 
///从当前位置读取4字节,转换为长整型 
///</summary> 
///<param name="offset"></param> 
///<returns></returns> 
#endregion 
private long readLong4(long offset) 

long ret = 0; 
ipFile.Position = offset; 
ret |= (ipFile.ReadByte() & 0xFF); 
ret |= ((ipFile.ReadByte() << 8) & 0xFF00); 
ret |= ((ipFile.ReadByte() << 16) & 0xFF0000); 
ret |= ((ipFile.ReadByte() << 24) & 0xFF000000); 
return ret; 


//根据当前位置,读取3字节 
#region 根据当前位置,读取3字节 
/**/ 
///<summary> 
///根据当前位置,读取3字节 
///</summary> 
///<param name="offset"></param> 
///<returns></returns> 
#endregion 
private long readLong3(long offset) 

long ret = 0; 
ipFile.Position = offset; 
ret |= (ipFile.ReadByte() & 0xFF); 
ret |= ((ipFile.ReadByte() << 8) & 0xFF00); 
ret |= ((ipFile.ReadByte() << 16) & 0xFF0000); 
return ret; 


//从当前位置读取3字节 
#region 从当前位置读取3字节 
/**/ 
///<summary> 
///从当前位置读取3字节 
///</summary> 
///<returns></returns> 
#endregion 
private long readLong3() 

long ret = 0; 
ret |= (ipFile.ReadByte() & 0xFF); 
ret |= ((ipFile.ReadByte() << 8) & 0xFF00); 
ret |= ((ipFile.ReadByte() << 16) & 0xFF0000); 
return ret; 


//取得begin和end之间的偏移量 
#region 取得begin和end之间的偏移量 
/**/ 
///<summary> 
///取得begin和end中间的偏移 
///</summary> 
///<param name="begin"></param> 
///<param name="end"></param> 
///<returns></returns> 
#endregion 
private long getMiddleOffset(long begin, long end) 

long records = (end - begin) / IP_RECORD_LENGTH; 
records >>= 1; 
if (records == 0) 
records = 1; 
return begin + records * IP_RECORD_LENGTH; 

} //class QQWry 

public class IPLocation 

public String country; 
public String area; 

public IPLocation() 

country = area = ""; 


public IPLocation getCopy() 

IPLocation ret = new IPLocation(); 
ret.country = country; 
ret.area = area; 
return ret; 


posted @ 2011-10-23 18:07  rob_2010  阅读(481)  评论(0)    收藏  举报