优化读取纯真IP数据库QQWry.dat获取地区信息
改自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获取地区信息的更多相关文章
- 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)
纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat) 转载自:http://blog.cafeboy.org/2011/02/25/qqwry-to-ipwry/ ht ...
- lib-qqwry v1.0 发布 nodejs解析纯真IP库(qqwry.dat)
lib-qqwry是当初学习node时用来练手的一个模块,用来解析纯真IP库的 现在发一个v1.0版本弥补我当时稚嫩的代码. 意外收获是,整理代码后发现,相比v0.x版本 急速模式下的效率提升大概20 ...
- 读取纯真IP数据库
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <stdli ...
- PHP获取IP及地区信息(纯真IP数据库)
昨天在写程序的时候,发现在用户的时候记录IP和地区信息也许以后用得上,去网上找了找,发现实现的方式有好多好多,因为我用的ThinkPHP,后来又去TP官网找了找,最后采用了下面这种方法. <?p ...
- PHP利用纯真IP数据库在本地实现IP地址信息查询
https://blog.csdn.net/myweishanli/article/details/45098693 准备工作: 建议本地IP地址数据库,请到http://www.cz88.net/这 ...
- 纯真IP数据库格式详解
纯真版IP数据库,优点是记录多,查询速度快,它只用一个文件QQWry.dat就包含了所有记录,方便嵌入到其他程序中,也方便升级.缺点是你想要编辑它却是比较麻烦的,由于其文件格式的限制,你要直接添加IP ...
- 纯真IP数据库格式详解 附demo
纯真版IP数据库,优点是记录多,查询速度快,它只用一个文件QQWry.dat就包含了所有记录,方便嵌入到其他程序中,也方便升级.缺点是你想要编辑它却是比较麻烦的,由于其文件格式的限制,你要直接添加IP ...
- python3通过纯真IP数据库查询IP归属地信息
在网上看到的别人写的python2的代码,修改成了python3. 把纯真IP数据库文件qqwry.dat放到czip.py同一目录下. #! /usr/bin/env python # -*- co ...
- PHP调用纯真IP数据库返回具体地址
function convertip($ip) { $ip1num = 0; $ip2num = 0; $ipAddr1 =""; $ipAddr2 =""; ...
随机推荐
- 【转】vs2017快捷键大全
最近接触到.net,用到vs2017,由于以前用的是eclipse,没有用过vs,加上又是日语版的,给工作带来了很多不便,于是网上查了vs2017的快捷键. 项目相关的快捷键 Ctrl + Shift ...
- md5Util
package com.rscode.credits.util; /** * MD5加密类 * @author 12 */ import java.security.MessageDigest; pu ...
- python学习笔记(1)python中的注释和安装python
注释 目标 注释的作用 单行注释 多行注释 01注释的作用 在程序中对代码的标注说明,增强代码的可读性 以 # 开头,# 右边的所有东西都被当做说明文字,而不是真正要执行的程序,只起到辅助说明作用 为 ...
- 总结描述用户和组管理类命令的使用方法,系统用户相关信息,取出主机IP地址
1.列出当前系统上所有已经登录的用户的用户名,注意:同一个用户登录多次,则只显示一次即可. [root@db146 ~]# who|cut -f1 -d' ' |sort -u root 2.取出最后 ...
- node.js同步读取与异步读取文件
- Linux 的终端及设置
Linux 的终端及设置 终端是一种字符型设备,有多种类型,通常使用tty 来简称各种类型的终端设备.终端特殊设备文件一般有以下几种: /dev/ttySn 串行端口终端 (Serial Port T ...
- 安装Oracle数据库心得
学到Oracle数据库了,想在自己电脑上安装个Oracle数据库.在网上下载了一个Oracle18c版 下边是我安装Oracle18c版的数据库失败,后来在卸载过程中遇到的问题: 1.用Univers ...
- [ZJOI2004]嗅探器
题目概要: 在无向图中寻找出所有的满足下面条件的点:割掉这个点之后,能够使得一开始给定的两个点a和b不连通,割掉的点不能是a或者b.(ZJOI2004) 数据范围约定结点个数N≤100边数M≤N*(N ...
- Linux第十一节课学习笔记
区域就是firewalld预先准备了几套防火墙策略集合(策略模板),用户可以根据生产场景的不同而选择合适的策略集合,从而实现防火墙策略之间的快速切换. RUNTIME模式:当前生效,重启失效:PERM ...
- MySQL Hardware--Linux 文件句柄限制
Linux会限制文件句柄数量,默认为1024,当超过该阈值后,会报"to many open files" ## 使用ulimit -a查看当前打开文件句柄限制 ulimit -a ...