C#读取QQWry.Dat文件实现IP查询
QQWry数据库下载地址:http://download.csdn.net/detail/fwj380891124/4385554
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; } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?