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;

        }

    }

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
本模块代码是针对在 2011 年在 CSDN 论坛个发布的“最新 NET 读取纯真IP数据库代码(C#)”源码,做了一次升级,这次升级不是简单的修补,是本人精心的重写,现在只需要 5 分哦,您值得拥有!该源代码不同于网上的代码,网上代码基本可分为两大类,第一类直接使用文件流,通过移动文件流指针(即更改 Stream.Position 属性值)搜索 IP 地址对应的信息,此类代码问题是:其一移动文件指针效率是比较低的(给 Position 赋值),多线程并发时,会重复打开多个文件效率更加底下;第二类是把文件直接加载内存中,通过这种缓冲,速度是提升了,但并没有为多线程环境优化,多线程并发时(如:Web 中每位访客,都是一根线程),意味会重复的读取文件,重复的创建缓存,浪费内存空间。 该源代码特点是考虑到了多线程应用环境(如:Web 每个会话,都是一根线程),设计了缓存对象 QQWryCache 用于管理缓存,用 QQCacheStream 流读取缓存数据。在多线程应用环境中,假设 10 根线程访问同一个纯真 IP 数据库时,只会开辟 1 份缓存,给多根线程共享,避免了不必要的内存浪费。 注1:本模块代码,保证所有静态方法都是线程安全的,但不保证所有实例方法都是线程安全的。 注2:每根线程访问缓存时,请通过 QQWryCache.GetCache 静态方法获取缓存对象。 注3:多根线程获取到的缓存对象,通常都是同一对象,该对象已经考虑了线程同步,不必担心线程安全问题。 /* >>> 使用完全缓存(缓存整个文件,约 8.8MB),调用方法如下: */ QQWryCache cache = QQWryCache.GetCache("qqwry.dat", true); Stream stream = cache.GetCacheStream(); QQWrySearcher searcher = new QQwryScanner(stream); QQWryLocation location = searcher.Query("IP 地址"); Console.WritleLine("Country = {0}, Location = {1}", location.Country, location.Location); /* 完全缓冲, * 缓存一旦初始化完毕,就会自动关闭文件, * 所以不再依赖于文件,因此可以不用关闭缓冲流, * 下面调用 Close 方法,其实没有实际意义,但也不会引发异常。 */ stream.Close(); /* >>> 使用索引缓存(仅缓存索引部分,约 3MB),调用方法如下: <<>> 直接使用文件流(不使用缓存),调用方法如下: <<>> 遍历 IP 数据库。 <<< */ QQWryCache cache = QQWryCache.GetCache("qqwry.dat", true); Stream stream = cache.GetCacheStream(); QQWrySearcher searcher = new QQWrySearcher(stream); // 用 for 循环遍历 for(int i = 0; i < searcher.Count; i++) { QQWryIpLocation item = searcher[i]; Console.WritleLine("Country = {0}, Location = {1}", location.Country, location.Location); } // 用 foreach 循环遍历 foreach(QQWryIpLocation item in searcher) { QQWryIpLocation item = searcher[i]; Console.WritleLine("Country = {0}, Location = {1}", location.Country, location.Location); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星火燎猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值