改自HeDaode 2007-12-28的代码

将之改为从硬盘读取后文件后,将MemoryStream放到内存中,提高后续查询速度

    ///<summary>
/// 提供从纯真IP数据库搜索IP信息的方法;
///</summary>
public class IPSearch
{
FileStream fileStream = null;
static long[] ipArray = null;
static long initPosition = ;
long ip;
static MemoryStream ipFile =null;
///<summary>
/// 构造函数
///</summary>
public IPSearch()
{
if (ipArray == null)
{
lock ("ip")
{
if (ipArray == null)
{
fileStream = new FileStream("f:/files/qqwry.dat", FileMode.Open, FileAccess.Read, FileShare.Read);
ipArray = BlockToArray(ReadIPBlock());
initPosition = fileStream.Position;
fileStream.Position = ;
byte[] bytes = new byte[fileStream.Length];
fileStream.Read(bytes, , bytes.Length); ipFile = new MemoryStream(bytes);
fileStream.Close();
fileStream = null;
bytes = null;
}
}
}
ipFile.Position = initPosition;
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//使.net core支持gb2312编码
} /// <summary>
/// 更新ip数据文件后,对内存中的流进行更新
/// </summary>
public void ClearStream()
{
ipFile.Close();
ipFile = null;
ipArray = null;
initPosition = ;
} ///<summary>
/// 获取指定IP所在地理位置
///</summary>
///<param name="strIP">要查询的IP地址</param>
///<returns></returns>
public string GetIPLocation(string strIP)
{
ip = IPToLong(strIP); long offset = SearchIP(ipArray, , ipArray.Length - ) * + ;
ipFile.Position += offset;//跳过起始IP
ipFile.Position = ReadLongX() + ;//跳过结束IP //IPLocation loc = new IPLocation();
int flag = ipFile.ReadByte();//读取标志
if (flag == )//表示国家和地区被转向
{
ipFile.Position = ReadLongX();
flag = ipFile.ReadByte();//再读标志
}
//long countryOffset = ipFile.Position;
string country = ReadString(flag); //if (flag == 2)
//{
// ipFile.Position = countryOffset + 3;
//}
//flag = ipFile.ReadByte();
//loc.area = ReadString(flag); //ipFile.Close();
//ipFile = null;
if (!country.Contains("市"))
{
return null;
}
if (!country.Contains("省"))
{
return country;
}
return country.Split("省")[];
}
///<summary>
/// 将字符串形式的IP转换位long
///</summary>
///<param name="strIP"></param>
///<returns></returns>
public long IPToLong(string strIP)
{
byte[] ip_bytes = new byte[];
string[] strArr = strIP.Split(new char[] { '.' });
for (int i = ; i < ; i++)
{
ip_bytes[i] = byte.Parse(strArr[ - i]);
}
return BitConverter.ToInt64(ip_bytes, );
}
///<summary>
/// 将索引区字节块中的起始IP转换成Long数组
///</summary>
///<param name="ipBlock"></param>
long[] BlockToArray(byte[] ipBlock)
{
long[] ipArray = new long[ipBlock.Length / ];
int ipIndex = ;
byte[] temp = new byte[];
for (int i = ; i < ipBlock.Length; i += )
{
Array.Copy(ipBlock, i, temp, , );
ipArray[ipIndex] = BitConverter.ToInt64(temp, );
ipIndex++;
}
return ipArray;
}
///<summary>
/// 从IP数组中搜索指定IP并返回其索引
///</summary>
///<param name="ipArray">IP数组</param>
///<param name="start">指定搜索的起始位置</param>
///<param name="end">指定搜索的结束位置</param>
///<returns></returns>
int SearchIP(long[] ipArray, int start, int end)
{
int middle = (start + end) / ;
if (middle == start)
return middle;
else if (ip < ipArray[middle])
return SearchIP(ipArray, start, middle);
else
return SearchIP(ipArray, middle, end);
}
///<summary>
/// 读取IP文件中索引区块
///</summary>
///<returns></returns>
byte[] ReadIPBlock()
{
long startPosition = StreamReadLongX();
long endPosition = StreamReadLongX();
long count = (endPosition - startPosition) / + ;//总记录数
fileStream.Position = startPosition;
byte[] ipBlock = new byte[count * ];
fileStream.Read(ipBlock, , ipBlock.Length);
fileStream.Position = startPosition;
return ipBlock;
}
///<summary>
/// 从IP文件中读取指定字节并转换位long
///</summary>
///<param name="bytesCount">需要转换的字节数,主意不要超过8字节</param>
///<returns></returns>
long StreamReadLongX(int bytesCount)
{
byte[] _bytes = new byte[];
fileStream.Read(_bytes, , bytesCount);
return BitConverter.ToInt64(_bytes, );
} ///<summary>
/// 从IP文件中读取指定字节并转换位long
///</summary>
///<param name="bytesCount">需要转换的字节数,主意不要超过8字节</param>
///<returns></returns>
long ReadLongX(int bytesCount)
{
byte[] _bytes = new byte[];
ipFile.Read(_bytes, , bytesCount); return BitConverter.ToInt64(_bytes, );
}
///<summary>
/// 从IP文件中读取字符串
///</summary>
///<param name="flag">转向标志</param>
///<returns></returns>
string ReadString(int flag)
{
if (flag == || flag == )//转向标志
ipFile.Position = ReadLongX();
else
ipFile.Position -= ; List<byte> list = new List<byte>();
byte b = (byte)ipFile.ReadByte();
while (b > )
{
list.Add(b);
b = (byte)ipFile.ReadByte();
} return Encoding.GetEncoding("gb2312").GetString(list.ToArray());
}
}

测试:

        [HttpPost("pt")]
public IActionResult PayTest([FromQuery]string ip)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
IPSearch iPSearch = new IPSearch();
string result = iPSearch.GetIPLocation(ip);
stopwatch.Stop();
return Ok(new { stopwatch.Elapsed,result});
}

第一次运行稍慢,以测试机的配置需要25~50毫秒之间

之后每次运行均在1毫秒以内

优化读取纯真IP数据库QQWry.dat获取地区信息的更多相关文章

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

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

  2. lib-qqwry v1.0 发布 nodejs解析纯真IP库(qqwry.dat)

    lib-qqwry是当初学习node时用来练手的一个模块,用来解析纯真IP库的 现在发一个v1.0版本弥补我当时稚嫩的代码. 意外收获是,整理代码后发现,相比v0.x版本 急速模式下的效率提升大概20 ...

  3. 读取纯真IP数据库

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <stdli ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 学习Linux的软件管理、进程管理

    一.软件管理 1.使用yum管理软件安装包 1.1什么是yum Yum (全称为:Yellow dog Updater, Modified) 由Duke University团队,修改Yellow D ...

  2. Unity VS 创建脚本自动添加头注释-时间-描述-作者等信息

    Unity生成脚本自动添加头注释 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心 ...

  3. python 11

    # 一.闭包 # # 判断:函数名.__closure__ # 若返回cell,则是闭包,返回None则不是闭包. # # 闭包:内层函数对外层函数非全局变量的引用就叫闭包. def func1(x) ...

  4. Function program language

    历史 Lambda演算为描述函数及其评估提供了理论框架.它是一种数学抽象而不是编程语言 - 但它构成了几乎所有当前函数式编程语言的基础.等效的理论公式,组合逻辑,通常被认为比lambda演算更抽象,并 ...

  5. xshell 使用命令上传、下载文件

    打开xshell, ①检查是否已经安装了上传下载的命令,#rpm -qa |grep lrzsz [root@mjy logs]# rpm -qa |grep lrzszlrzsz-0.12.20-2 ...

  6. js···元素的属性

    Div.attributes 是所有标签属性构成的数据集合 Div.classList 是所有class名构成的数组集合 在classList的原型链上看以看到add()和remove(). clie ...

  7. 1130-Host '192.168.0.105' is not allowed to connect to this MySQL server的解决方案

    在CentOS 7服务器(192.168.0.118)上安装mysql5.7.17后,在本地(192.168.0.105)通过Navicat连接服务器上的MySQL报错,报错如图所示: Paste_I ...

  8. 【学习】C++多态机制

    多态:静态(早绑定) 在编译阶段和链接就能确定功能调用的函数.     动态(晚绑定) 在程序运行时根据需要的功能确定调用的函数. 实现晚绑定就要定义虚函数,使用虚函数则会用到基类指针. 继承基类虚成 ...

  9. 学习笔记CB012: LSTM 简单实现、完整实现、torch、小说训练word2vec lstm机器人

    真正掌握一种算法,最实际的方法,完全手写出来. LSTM(Long Short Tem Memory)特殊递归神经网络,神经元保存历史记忆,解决自然语言处理统计方法只能考虑最近n个词语而忽略更久前词语 ...

  10. C#编码规范之代码的增删改约定

    增加 ,仅增加一行时可以是这样"int a = GetScale(obj, col); // 描述.add by Tome 2018-9-20",多行时见下. #region ad ...