纯真IP库在C#中需内存加载QQWry.dat并用GB18030编码解析,避免句柄耗尽、线程干扰与乱码;查询返回竖线分隔字符串,地域取倒数第4位,须校验MD5防文件损坏。
纯真ip库在c#里不能直接用官方提供的qqwry.dat做高并发解析——它没内置线程安全,也没索引加速,硬读会卡死或返回空。
为什么 QQWry.dat 不能直接用 FileStream + BinaryReader 每次都打开读?
纯真数据库是偏移寻址结构,每次查询要先读索引区、再跳转读记录区。如果每次都 new FileStream("QQWry.dat", FileMode.Open),文件句柄开闭频繁,Windows下容易触发句柄耗尽;更关键的是,QQWry.dat 的索引块不带校验,多线程同时读同一文件流会互相干扰指针位置,导致解析出错(比如城市变成“???”或空字符串)。
- 必须把整个
QQWry.dat加载进内存(byte[]),所有查询基于该数组操作 - 索引区固定在文件开头0x100–0x200之间,但实际起始偏移需靠末尾的0x1A字节定位,不能硬写0x100
- 查不到时返回空字符串不是bug,是纯真库本身行为——它只收录有明确归属的IP段,内网/保留地址/新分配段大概率无记录
怎么用 IPSearcher 类避免 NullReferenceException 和乱码?
网上很多“源码”直接用 Encoding.Default 解码IP记录,结果在UTF-8环境(如Linux容器、VS Code终端)下城市名全是问号。纯真库正文是GB18030编码(兼容GBK),不是系统默认编码。
- 初始化时必须用
Encoding.GetEncoding("GB18030"),别用Encoding.UTF8或Encoding.Default -
IPSearcher实例要单例复用,不要每次请求 new 一个——它的indexBuffer和dataBuffer是大数组,GC压力大 - 传入IP必须是标准点分十进制字符串,
"127.0.0.1"行,"::1"或"127.0.0.1:8080"不行,得提前截断 - 查不到时方法返回
null或空字符串,别直接.Split('|'),先判空
FindIP 返回的字符串格式到底是什么?怎么安全拆解?
纯真库返回形如 "中国|0|北京市|市辖区|电信|0|0" 的竖线分隔串,但字段数不固定:部分记录只有4段(如 "中国|0|香港特别行政区|0"),IPv6映射段可能多出“运营商”字段。硬按索引取 parts[2] 城市会越界。
- 始终用
string.Split('|', StringSplitOptions.None),保留空段 - 地域字段实际在倒数第4位(即
parts[^4]),不是第3位——因为末尾两个“0”可能被省略,但前导国家、区域、城市三段是稳定的 - 运营商信息在倒数第2位(
parts[^2]),但很多老数据是"0",别当成有效值用 - 示例:
var parts = result?.Split('|') ?? Array.Empty<string>(); var city = parts.Length >= 4 ? parts[^4] : "";</string>
最麻烦的其实是更新——QQWry.dat 没版本号,没法自动判断是否过期;手动下载后若没校验MD5,可能载入半截损坏文件,导致所有查询返回空。这个点没人提,但线上跑一周后突然全变“未知地区”,八成是文件换错了。


















