private IPLocation getIPLocation(int offset) {
// 跳过4字节ip
mbb.position(offset + 4);
// 读取第一个字节判断是否标志字节
byte b = mbb.get();
if(b == REDIRECT_MODE_1) {
// 读取国家偏移
int countryOffset = readInt3();
// 跳转至偏移处
mbb.position(countryOffset);
// 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
b = mbb.get();
if(b == REDIRECT_MODE_2) {
loc.setCountry ( readString(readInt3()));
mbb.position(countryOffset + 4);
} else
loc.setCountry ( readString(countryOffset));
// 读取地区标志
loc.setArea(readArea(mbb.position()));
} else if(b == REDIRECT_MODE_2) {
loc.setCountry ( readString(readInt3()));
loc.setArea(readArea(offset + 8));
} else {
loc.setCountry ( readString(mbb.position() - 1));
loc.setArea(readArea(mbb.position()));
}
return loc;
}
private String readArea(long offset) throws IOException {
ipFile.seek(offset);
byte b = ipFile.readByte();
if(b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
long areaOffset = readLong3(offset + 1);
if(areaOffset == 0)
return Message.unknown_area;
else
return readString(areaOffset);
} else
return readString(offset);
}
private String readArea(int offset) {
mbb.position(offset);
byte b = mbb.get();
if(b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
int areaOffset = readInt3();
if(areaOffset == 0)
return Message.unknown_area;
else
return readString(areaOffset);
} else
return readString(offset);
}
private String readString(long offset) {
try {
ipFile.seek(offset);
int i;
for(i = 0, buf[i] = ipFile.readByte(); buf[i] != 0; buf[++i] =
ipFile.readByte());
if(i != 0)
return Util.getString(buf, 0, i, "GBK");
} catch (IOException e) {
LogFactory.log("",Level.ERROR,e);
}
return "";
}
private String readString(int offset) {
try {
mbb.position(offset);
int i;
for(i = 0, buf[i] = mbb.get(); buf[i] != 0; buf[++i] =
mbb.get());
if(i != 0)
return Util.getString(buf, 0, i, "GBK");
} catch (IllegalArgumentExceptione) {
LogFactory.log("",Level.ERROR,e);
}
return "";
}
}
在实际项目用我使用spring注入IP地址库文件的名字和所在目录,并能保证IPSeeker的单一实例。
下面是个工具类,把string和btye数组之间互相转换的类。
Java代码
package com.showtime.IPparse;
import java.io.UnsupportedEncodingException;
import java.util.StringTokenizer;
import org.apache.log4j.Level;
import com.showtime.util.LogFactory;
public class Util {
private static StringBuilder sb = new StringBuilder();
public static byte[] getIpByteArrayFromString(String ip) {
byte[] ret = new byte[4];
StringTokenizer st = new 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) {
LogFactory.log("从ip的字符串形式得到字节数组形式报错", Level.ERROR, e);
}
return ret;
}
public static String getIpStringFromBytes(byte[] ip) {
sb.delete(0, sb.length());
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();
}
public static String getString(byte[] b, int offset, int len,
String encoding) {
try {
return new String(b, offset, len, encoding);
} catch (UnsupportedEncodingException e) {
return new String(b, offset, len);
}
}
}
package com.showtime.IPparse;
import java.io.UnsupportedEncodingException;
import java.util.StringTokenizer;
import org.apache.log4j.Level;
import com.showtime.util.LogFactory;
public class Util {
private static StringBuilder sb = new StringBuilder();
public static byte[] getIpByteArrayFromString(String ip) {
byte[] ret = new byte[4];
StringTokenizer st = new 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) {
LogFactory.log("从ip的字符串形式得到字节数组形式报错", Level.ERROR, e);
}
return ret;
}
public static String getIpStringFromBytes(byte[] ip) {
sb.delete(0, sb.length());
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();
}
public static String getString(byte[] b, int offset, int len,
String encoding) {
try {
return new String(b, offset, len, encoding);
} catch (UnsupportedEncodingException e) {
return new String(b, offset, len);
}
}
}
下面是个常量值的类,用接口形式来定义省事不少。
Java代码
package com.showtime.IPparse;
public interface Message {
String bad_ip_file="IP地址库文件错误";
String unknown_country="未知国家";
String unknown_area="未知地区";
}
package com.showtime.IPparse;
public interface Message {
String bad_ip_file="IP地址库文件错误";
String unknown_country="未知国家";
String unknown_area="未知地区";
}
一个封装国家和地区的实体类
Java代码
package com.showtime.IPparse;
public class IPLocation {
private String country;
private String area;
public IPLocation() {
country = area = "";
}
public IPLocation getCopy() {
IPLocation ret = new IPLocation();
ret.country = country;
ret.area = area;
return ret;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getArea() {
return area;
}
public void setArea(String area) {
//如果为局域网,纯真IP地址库的地区会显示CZ88.NET,这里把它去掉
if(area.trim().equals("CZ88.NET")){
this.area="本机或本网络";
}else{
this.area = area;
}
}
}
package com.showtime.IPparse;
public class IPLocation {
private String country;
private String area;
public IPLocation() {
country = area = "";
}
public IPLocation getCopy() {
IPLocation ret = new IPLocation();
ret.country = country;
ret.area = area;
return ret;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getArea() {
return area;
}
public void setArea(String area) {
//如果为局域网,纯真IP地址库的地区会显示CZ88.NET,这里把它去掉
if(area.trim().equals("CZ88.NET")){
this.area="本机或本网络";
}else{
this.area = area;
}
}
}
一下是一个范围记录的类
Java代码
package com.showtime.IPparse;
public class IPEntry {
public String beginIp;
public String endIp;
public String country;
public String area;
public IPEntry() {
beginIp = endIp = country = area = "";
}
}
package com.showtime.IPparse;
public class IPEntry {
public String beginIp;
public String endIp;
public String country;
public String area;
public IPEntry() {
beginIp = endIp = country = area = "";
}
}
日志记录类
Java代码
package com.showtime.util;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class LogFactory {
private static final Logger logger;
static {
logger = Logger.getLogger("stdout");
logger.setLevel(Level.DEBUG);
}
public static void log(String info, Level level, Throwable ex)
{
logger.log(level, info, ex);
}
public static Level getLogLevel(){
return logger.getLevel();
}
}
package com.showtime.util;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class LogFactory {
private static final Logger logger;
static {
logger = Logger.getLogger("stdout");
logger.setLevel(Level.DEBUG);
}
public static void log(String info, Level level, Throwable ex)
{
logger.log(level, info, ex);
}
public static Level getLogLevel(){
return logger.getLevel();
}
}
下面是测试类
Java代码
package com.showtime.IPparse;
import junit.framework.TestCase;
public class IPtest extends TestCase {
public void testIp(){
//指定纯真数据库的文件名,所在文件夹
IPSeeker ip=new IPSeeker("QQWry.Dat","f:/qqwry");
//测试IP 58.20.43.13
System.out.println(ip.getIPLocation("58.20.43.13").getCountry()+":"+ip.getIPLocation("58.20.43.13").getArea());
}
}