根据IP判断地理位置
- 首先,当然是要有IP数据库,指明某一段IP代表哪个地方,本文采用的是txt格式的数据文件
- IP数据库中的IP全部转换成了Long型,并且经过排序,这是为了方便二分查找
初始化操作: 载入IP数据文件
将数据文件按行读入内存,IP数据文件的格式如下:
起始IP | 结束IP | 国家 | 省 | 市 | 区 | 未知 | 运营商 |
---|---|---|---|---|---|---|---|
10000000 | 20000000 | 中国 | 北京市 | 北京市 | 海淀区 | 未知 | 电信 |
读取文件:
ipFile = new File(Class.forName("IPMapping").getClassLoader().getResource("ip_standard.txt").getFile());
List<String> lines = null;
lines = Files.readLines(ipFile, Charsets.UTF_8);
遍历每一行信息后存放在ImmutableList
中:
static ImmutableList<Long> START_IP_INDEX;
static ImmutableList<Long> END_IP_INDEX;
static ImmutableList<String> IP_INFO;
START_IP_INDEX = new ImmutableList.Builder<Long>().addAll(startIpIndexTmp.iterator()).build();
END_IP_INDEX = new ImmutableList.Builder<Long>().addAll(endIpIndexTmp.iterator()).build();
IP_INFO = new ImmutableList.Builder<String>().addAll(ipInfoTmp.iterator()).build();
判断IP的准确性
需要查找的IP为标准的XXX.XXX.XXX.XXX
格式
在进行查找之前需要判断该IP字符串是否有效:
public static boolean isValid(String ipStr) {
if (StringUtils.isBlank(ipStr))
return false;
final String IP_FORMAT = "((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
return (ipStr.matches(IP_FORMAT)) ? true : false;
}
有效的IP字符串可以转化成Long型
public static long ip2long(String ipStr) {
Long ipInLong = 0L;
if (isValid(ipStr)) {
String[] partIp = StringUtils.split(ipStr.trim(), "\\.");
for (int i = 0; i < 4; i++)
ipInLong = ipInLong << 8 | Integer.parseInt(partIp[i]);
}
return ipInLong;
}
通过二分查找判断该IP是否有对应的信息
和普通的二分相比,键的值是一对数,而且这对数的左值小于等于右值
改下了二分查找如下:
public int binarySearch(long ip) {
int low = 0;
int high = START_IP_INDEX.size() - 1;
while (low <= high) {
int middle = (low + high) / 2;
if (ip >= START_IP_INDEX.get(middle) && (ip <= END_IP_INDEX.get(middle)))
return middle;
if (ip < START_IP_INDEX.get(middle))
high = middle - 1;
else
low = middle + 1;
}
return -1;
}