
使用纯真IP库(CZ88)识别IP归属地,主要有两种方式:一种是传统的基于QQWry.dat文件的解析,另一种是官方推出的新版CZDB格式。下面我将详细介绍这两种方法,你可以根据自己的技术栈和需求选择。
请注意:纯真免费版IP库遵循GPLv3开源协议,这意味着你可以免费使用,但如果用于商业用途或研制闭源的同类产品,则需要留意协议约束或考虑使用其商业版API。
目前使用纯真IP库主要有两种方式,区别如下:
对比项 | 传统方式 (QQWry.dat) | 新方式 (CZDB + 密钥) |
|---|---|---|
数据格式 | 旧的 .dat 格式 | 新的 .czdb 格式 |
获取方式 | 从第三方网站或工具获取,官方已不再提供直接下载 | 需在官网注册账号并申请授权密钥后下载 |
支持IP类型 | IPv4 | IPv4和IPv6双支持 |
解析复杂度 | 较高,需要手动解析二进制文件格式 | 较低,官方提供各语言的解析库,开箱即用 |
维护难度 | 一般,需要手动更新.dat文件 | 简单,使用官方工具和密钥可方便地管理更新 |
这种方法适合习惯使用旧版文件,或在没有官网密钥的情况下使用。
QQWry.dat 文件。虽然纯真官网已不再提供此格式的直接下载,但你可以通过网络搜索找到该文件的资源,或使用一些工具进行更新和导出。
QQWry.dat文件,并读取文件头部的索引区起始和结束位置,计算出总的IP记录条数。114.114.114.114)通过ip2long()函数转换为一个长整数,方便进行范围比较。iconv(GBK, UTF-8//IGNORE, $location)函数将其转换为UTF-8,以防止乱码。网上有许多成熟的PHP实现可以参考,你可以在例如阿里云开发者社区等平台找到完整的类代码。
使用Java代码解析 QQWry.dat 文件来查询IP归属地,核心在于理解其二进制文件结构并进行解析。这里为你提供一套完整的、可直接运行的代码实现。
这套代码主要包含三个核心部分:IP记录实体类、字节转换工具类,以及执行查询的主类 IPSeeker。
IPEntry.java这个类用于封装一个IP段及其对应的地理位置信息。
/**
* 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP
*/
public class IPEntry {
public String beginIp; // 起始IP
public String endIp; // 结束IP
public String country; // 国家
public String area; // 区域
public IPEntry() {
beginIp = endIp = country = area = "";
}
@Override
public String toString() {
return "IP范围:" + this.beginIp + "-" + this.endIp + " " + this.country + " " + this.area;
}
}Utils.java提供IP地址与byte数组之间转换的方法。
import java.io.UnsupportedEncodingException;
/**
* 工具类,提供IP和字节数组转换等方法
*/
public class Utils {
/**
* 从字节数组的指定位置读取一个以\0结尾的字符串
* @param b 字节数组
* @param offset 起始位置
* @param maxLength 最大长度,防止无限循环
* @return 读取的字符串(GBK编码)
*/
public static String getString(byte[] b, int offset, int maxLength) {
int i = offset;
// 找到字符串结束符 \0 的位置
while (i < offset + maxLength && b[i] != 0) {
i++;
}
// 如果找到了\0,则长度是i-offset;否则长度为maxLength
int len = (i == offset + maxLength) ? maxLength : i - offset;
if (len == 0) {
return "";
}
try {
// 纯真IP库使用GBK编码
return new String(b, offset, len, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return new String(b, offset, len);
}
}
/**
* 将字符串形式的IP转换为byte数组
* @param ip 如 "127.0.0.1"
* @return byte[4] 数组
*/
public static byte[] getIpByteArrayFromString(String ip) {
byte[] ret = new byte[4];
java.util.StringTokenizer st = new java.util.StringTokenizer(ip, ".");
try {
ret[0] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
ret[1] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
ret[2] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
ret[3] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
} catch (Exception e) {
System.out.println("IP地址格式错误: " + ip);
}
return ret;
}
/**
* 将byte数组形式的IP转换为字符串
* @param ip byte[4] 数组
* @return 如 "127.0.0.1"
*/
public static String getIpStringFromBytes(byte[] ip) {
StringBuilder sb = new StringBuilder();
sb.append(ip[0] & 0xFF);
sb.append('.');
sb.append(ip[1] & 0xFF);
sb.append('.');
sb.append(ip[2] & 0xFF);
sb.append('.');
sb.append(ip[3] & 0xFF);
return sb.toString();
}
}IPSeeker.java这是解析 QQWry.dat 并执行查询的主要类,包含了文件解析、二分查找、缓存和编码转换的全部逻辑。
import java.io.*;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.ut