利用纯真数据库根据IP定位地区

        在系统中,查看用户的登录信息是一个很常见的功能。我们往往会记录下用户计算机的IP和地理位置,然而IP地址记录非常容易,但是地理位置相对来说较难。开始,菜鸟是想创建一个IP地址库,根据IP地址库查找相应的地理位置。后来想有没有一个相对完整的IP地址库供菜鸟使用了,于是找到了一个QQwry.dat(纯真数据库)。然而,QQwry.dat是什么呢?以及怎么使用?菜鸟通过各位大神的笔记终于弄懂了,以致写下这篇文章供和我一样的菜鸟学习。

一、纯真数据库(QQwry.dat)

1.基本结构

        QQwry.dat文件在结构上分为文件头、记录区和索引区3部分。我们一般在使用时先从索引区查找记录偏移,根据记录偏移在从记录区中获取。由于记录区是不定长的,且比较多,因此,一般采用二分查找法进行查找。

2.文件头

        QQwry.dat文件的头文件结构非常简单,为8个字节。前4个字节为第一条索引的绝对偏移,后4个字节为最后一条索引的绝对偏移。

3.记录区

        每条IP地址的记录区都由国家和地区组成,但是在这里国家和地区都不太明确,相对而言的。国家可能是指一所学校,地区可能指学校中的某一系。于是我们想着IP地址的记录格式可能为:[IP地址][国家名称][地区名称]。

        国家和地区可能有很多重复,因此我们我可以用重定向来节约空间。其重定向有两种方式:一种是直接用字符串表示国家或地区;另一种是一个4字节的结构,第1个字节表示重定向的模式,后3个字节表示国家名称或地区名称的实际偏移位置。

        重定向的模式分为两种:一种是只有国家,没有地区,也就是说地区记录跟着国家记录走了,在IP地址之后只剩下国家记录的4个字节,后3个字节是一个指针,指向了实际的国家名称,其标识字节为0X01。另一种是既有国家又有地址,即地区记录没有跟着国家记录走。在4个字节的国家记录后还含有地区记录,其标识字节为0X02。

4.索引区

        通过了解“文件头”,我们可以了解到文件头实际上是两个指针,分别指向文件的第一条索引和最后一条索引的绝对偏移。我们可以根据头文件定位到索引区,然后开始查找IP。每条索引区为7个字节,前4个字节表示起始IP地址,后3个字节表示结束IP地址。如222.11.0.1-222.11.0.240,222.11.0.1表示起始IP地址,222.11.0.240表示结束IP地址。若我们要查找的IP地址在这个IP地址的范围内,则根据这条索引区查找国家和地区。

二、实例

1.IP地址实体,包含起始、结束IP、国家名称和地区名称

package com.test.ip.entity;

public class IpEntity {
	private String startIp;// 起始IP
	private String endIp;// 结尾IP
	private String country;// 国家
	private String area;// 区域

	// 構造方法:清空数据信息
	public IpEntity() {
		super();
		this.startIp = "";
		this.endIp = "";
		this.country = "";
		this.area = "";
	}

	// getter和setter方法提供属性对外访问接口
	public String getStartIp() {
		return startIp;
	}

	public void setStartIp(String startIp) {
		this.startIp = startIp;
	}

	public String getEndIp() {
		return endIp;
	}

	public void setEndIp(String endIp) {
		this.endIp = endIp;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getArea() {
		return area;
	}

	public void setArea(String area) {
		this.area = area;
	}

}

2.位置实体

package com.test.ip.entity;

/**
 * 封装IP信息,如国家和地区
 * 
 * @author aleyn
 *
 */
public class IpLocation {
	private String country;// 国家
	private String area;// 地区

	// 构造方法
	public IpLocation() {
		this.country = "";
		this.area = "";
	}

	public IpLocation getCopy() {
		IpLocation ipLocation = new IpLocation();
		ipLocation.setCountry(this.getCountry());
		ipLocation.setArea(this.getArea());
		return ipLocation;
	}

	// getter、setter
	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;
		}
	}

}

3.转换工具类

package com.test.ip.util;

import java.util.StringTokenizer;

/**
 * 转换工具
 * 
 * @author aleyn
 *
 */
public class ConvertUtils {
	private static StringBuffer sb = new StringBuffer();

	/**
	 * IP字符串转字节数组
	 * 
	 * @param ip
	 * @return
	 */
	public static byte[] getIpArray(String ip) {
		byte[] buffer = new byte[4];
		StringTokenizer stringTokenizer = new StringTokenizer(ip, ".");
		try {
			buffer[0] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
			buffer[1] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
			buffer[2] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
			buffer[3] = (byte) (Integer.parseInt(stringTokenizer.nextToken()) & 0xFF);
		} catch (Exception e) {
			e.printStackTrace(); 
		}
		return buffer;
	}

	/**
	 * IP字节数组换字符串
	 * 
	 * @param ip
	 * @return
	 */
	public static String getIpString(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();
	}

	/**
	 * 根据某种编码将IP字节数组转为字符串
	 * 
	 * @param ip
	 * @param offset
	 * @param length
	 * @param encode
	 * @return
	 */
	public static String getIpString(byte[] ip, int offset, int length,
			String encode) {
		try {
			return new String(ip, offset, length, encode);
		} catch (Exception e) {
			return new String(ip, offset, length);
		}
	}
}

4.读取国家或地区工具类

package com.test.ip.util;

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;

public class ReadUtils {
	/**
	 * 从offset未知读取一个4字节为一个long java格式为big-endian
	 * 
	 * @param offset
	 * @return
	 */
	public static long readLongByFour(RandomAccessFile randomAccessFile,
			long offset) {
		long result = 0;
		try {
			randomAccessFile.seek(offset);
			result |= (randomAccessFile.readByte() & 0xFF);
			result |= ((randomAccessFile.readByte() << 8) & 0xFF00);
			result |= ((randomAccessFile.readByte() << 16) & 0xFF0000);
			result |= ((randomAccessFile.readByte() << 24) & 0xFF000000);
			return result;
		} catch (Exception e) {
			return -1;
		}
	}

	/**
	 * 从offset位置开始读取3个字节为一个long
	 * 
	 * @param randomAccessFile
	 * @param offset
	 * @param buffer
	 * @return
	 */
	public static long readLongByThree(RandomAccessFile randomAccessFile,
			long offset, byte[] buffer) {
		long result = 0;
		try {
			randomAccessFile.seek(offset);
			randomAccessFile.readFully(buffer);
			result |= (buffer[0] & 0xFF);
			result |= ((buffer[1] << 8) & 0xFF00);
			result |= ((buffer[2] << 16) & 0xFF0000);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	/**
	 * 从当前位置读取3个字节为一个long
	 * 
	 * @param randomAccessFile
	 * @param buffer
	 * @return
	 */
	public static long readLongByThree(RandomAccessFile randomAccessFile,
			byte[] buffer) {
		long result = 0;
		try {
			randomAccessFile.readFully(buffer);
			result |= (buffer[0] & 0xFF);
			result |= ((buffer[1] << 8) & 0xFF00);
			result |= ((buffer[2] << 16) & 0xFF0000);
			return result;
		} catch (Exception e) {
			return -1;
		}
	}

	/**
	 * 从内存映射的offset位置,开始3个字节读取一个int
	 * 
	 * @param offset
	 * @return
	 */
	public static int readIntByThree(MappedByteBuffer mappedByteBuffer,
			int offset) {
		mappedByteBuffer.position(offset);
		return mappedByteBuffer.getInt() & 0x00FFFFFF;
	}

	/**
	 * 从内存映射的当前位置,开始3个字节读取一个int
	 * 
	 * @param mappedByteBuffer
	 * @return
	 */
	public static int readIntByThree(MappedByteBuffer mappedByteBuffer) {
		return mappedByteBuffer.getInt() & 0x00FFFFFF;
	}

	/**
	 * 从offset位置读取4个字节的IP地址放入IP数组中,读取后的IP地址格式为big-endian
	 * 
	 * @param offset
	 * @param ip
	 */
	public static void readIp(RandomAccessFile randomAccessFile, long offset,
			byte[] ip) {
		try {
			randomAccessFile.seek(offset);
			randomAccessFile.readFully(ip);
			byte temp = ip[0];
			ip[0] = ip[3];
			ip[3] = temp;
			temp = ip[1];
			ip[1] = ip[2];
			ip[2] = temp;
		} catch (Exception e) {
			e.printStackTrace(); 
		}
	}

	/**
	 * 从offset位置读取一个以0结束的字符串
	 * 
	 * @param offset
	 * @return
	 */
	public static String readString(RandomAccessFile randomAccessFile,
			long offset, byte[] buffer) {
		try {
			randomAccessFile.seek(offset);
			int i;
			for (i = 0, buffer[i] = randomAccessFile.readByte(); buffer[i] != 0; buffer[++i] = randomAccessFile
					.readByte())
				;
			if (i != 0) {
				return ConvertUtils.getIpString(buffer, 0, i, "GBK");
			}
		} catch (Exception e) {
			e.printStackTrace(); 
		}
		return "";
	}

	/**
	 * 从offset位置读取一个以0结束的字符串
	 * 
	 * @param offset
	 * @return
	 */
	public static String readString(MappedByteBuffer mappedByteBuffer,
			int offset, byte[] buffer) {
		try {
			mappedByteBuffer.position(offset);
			int i;
			for (i = 0, buffer[i] = mappedByteBuffer.get(); buffer[i] != 0; buffer[++i] = mappedByteBuffer
					.get())
				;
			if (i != 0)
				return ConvertUtils.getIpString(buffer, 0, i, "GBK");
		} catch (IllegalArgumentException e) {
			e.printStackTrace(); 
		}
		return "";
	}

	/**
	 * 从offset位置读取4个字节的IP地址放入IP数组中,读取后的IP地址格式为big-endian
	 * 
	 * @param mappedByteBuffer
	 * @param offset
	 * @param ip
	 */
	public static void readIp(MappedByteBuffer mappedByteBuffer, int offset,
			byte[] ip) {
		try {
			mappedByteBuffer.position(offset);
			mappedByteBuffer.get(ip);
			byte temp = ip[0];
			ip[0] = ip[3];
			ip[3] = temp;
			temp = ip[1];
			ip[1] = ip[2];
			ip[2] = temp;
		} catch (Exception e) {
			e.printStackTrace(); 
		}
	}

	/**
	 * 比较两个字节的大小
	 * 
	 * @param b1
	 * @param b2
	 * @return
	 */
	private static int compareByte(byte b1, byte b2) {
		if ((b1 & 0xFF) > (b2 & 0xFF)) // 比较是否大于
			return 1;
		else if ((b1 ^ b2) == 0)// 判断是否相等
			return 0;
		else
			return -1;
	}

	/**
	 * 将要查询的IP和起始的IP进行比较
	 * 
	 * @param ip
	 * @param beginIp
	 * @return
	 */
	public static int compareIp(byte[] ip, byte[] beginIp) {
		for (int i = 0; i < 4; i++) {
			int j = compareByte(ip[i], beginIp[i]);
			if (j != 0) {
				return j;
			}
		}
		return 0;
	}
}

5.提示消息

package com.test.ip.util;

/**
 * 提示信息
 * 
 * @author aleyn
 *
 */
public interface Message {
	public static final String BAD_IP_FILE = "IP地址库文件错误";
	public static final String UNKNOW_COUNTRY = "未知国家";
	public static final String UNKNOW_AREA = "未知区域";
}

6.IP查看器

package com.test.ip.viewer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.test.ip.entity.IpEntity;
import com.test.ip.entity.IpLocation;
import com.test.ip.util.ConvertUtils;
import com.test.ip.util.LogFactory;
import com.test.ip.util.Message;
import com.test.ip.util.ReadUtils;

public class IpViewer {
	private String fileName = "qqwry.dat";// 纯真IP数据库名
	private String fileDir = null;// 保存的文件夹

	// 固定常量,如记录长度
	private static final int IP_RECORD_LENGTH = 7;
	private static final byte REDIRECT_MODE_ONE = 0x01;
	private static final byte REDIRECT_MODE_TWO = 0x02;

	// 缓存已经查找过的IP地址,避免二次查找,加快速度
	private Map cache;
	// 随机文件访问类
	private RandomAccessFile randomAccessFile;
	// 内存映射文件
	private MappedByteBuffer mappedByteBuffer;
	// 起始地区的开始和结束绝对偏移量
	private long begin, end;

	// 为提高效率,临时变量
	private IpLocation ipLocation;
	private byte[] buffer;
	private byte[] bufferOne;
	private byte[] bufferTwo;

	/**
	 * 初始化
	 */
	public IpViewer() {
		// 获取文件路径和名称
		String path = IpViewer.class.getResource("").getPath() + fileName;
		fileName = path;
		// 初始化变量
		this.cache = new HashMap();
		this.ipLocation = new IpLocation();
		this.buffer = new byte[100];
		this.bufferOne = new byte[3];
		this.bufferTwo = new byte[4];

		try {
			randomAccessFile = new RandomAccessFile(fileName, "r");
		} catch (FileNotFoundException e) {
			// 若文件找不到,在当前目录下重新搜索,并将文件名全部改为小写(有些系统只能识别小写)
			String name = new File(fileName).getName().toLowerCase();
			File[] files = new File(fileDir).listFiles();
			for (int i = 0; i < files.length; i++) {
				// 判断是否是文件
				if (files[i].isFile()) {
					// 判断文件名称
					if (files[i].getName().toLowerCase().equals(name)) {
						try {
							randomAccessFile = new RandomAccessFile(files[i],
									"r");
						} catch (FileNotFoundException fileNotFoundException) {
							e.printStackTrace();
							fileName = null;
						}
						break;
					}
				}
			}
		}

		// 若文件打开成功,读取文件头信息
		if (randomAccessFile != null) {
			try {
				begin = ReadUtils.readLongByFour(randomAccessFile, 0);
				end = ReadUtils.readLongByFour(randomAccessFile, 4);
				if (begin == -1 || end == -1) {
					randomAccessFile.close();
					randomAccessFile = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
				randomAccessFile = null;
			}
		}
	}

	/**
	 * 给定一个不完全的地点名称,得到包含该地点的IP范围记录
	 * 
	 * @param str
	 * @return
	 */
	public List getIpEntityDebug(String str) {
		List list = new ArrayList();
		long endOffset = end + 4;
		for (long offset = begin + 4; offset < endOffset; offset += IP_RECORD_LENGTH) {
			// 读取结束IP偏移量
			long temp = ReadUtils.readLongByThree(randomAccessFile, offset,
					bufferOne);
			// 若temp不等于-1,则读取IP信息
			if (temp != -1) {
				IpLocation ipLocation = this.getIpLocation(temp);
				// 判断是否包含改地名,若包含,择添加到list
				if (ipLocation.getCountry().indexOf(str) != -1
						|| ipLocation.getArea().indexOf(str) != -1) {
					IpEntity ipEntity = new IpEntity();
					ipEntity.setCountry(ipLocation.getCountry());
					ipEntity.setArea(ipLocation.getArea());
					// 获取起始IP
					ReadUtils.readIp(randomAccessFile, offset - 4, bufferTwo);
					ipEntity.setStartIp(ConvertUtils.getIpString(bufferTwo));
					// 获取结束IP
					ReadUtils.readIp(randomAccessFile, temp, bufferTwo);
					ipEntity.setEndIp(ConvertUtils.getIpString(bufferTwo));
					list.add(ipEntity);
				}
			}
		}
		return list;
	}

	public List getIpEntity(String s) {

		List list = new ArrayList();
		try {
			// 映射IP信息文件到内存中
			if (mappedByteBuffer == null) {
				FileChannel fc = randomAccessFile.getChannel();
				mappedByteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0,
						randomAccessFile.length());
				mappedByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
			}

			int endOffset = (int) end;
			for (int offset = (int) begin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
				int temp = ReadUtils.readIntByThree(mappedByteBuffer, offset);
				if (temp != -1) {
					IpLocation location = this.getIpLocation(temp);
					// 地点是否包含要查找的地点名称
					if (location.getCountry().indexOf(s) != -1
							|| location.getArea().indexOf(s) != -1) {
						IpEntity entity = new IpEntity();
						entity.setCountry(location.getCountry());
						entity.setArea(location.getArea());
						// 得到起始IP
						ReadUtils.readIp(mappedByteBuffer, offset, bufferTwo);
						entity.setStartIp(ConvertUtils.getIpString(bufferTwo));
						// 得到结束IP
						ReadUtils.readIp(mappedByteBuffer, temp, bufferTwo);
						entity.setEndIp(ConvertUtils.getIpString(bufferTwo));
						// 添加该记录
						list.add(entity);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace(); 
		}
		return list;
	}

	/**
	 * 获取IP所在的地区信息
	 */
	public IpLocation getIpLocation(String ip) {
		IpLocation location = new IpLocation();
		location.setCountry(this.getCountry(ip));
		location.setArea(this.getArea(ip));
		return location;
	}

	/**
	 * 根据IP地区偏移量,获取IP信息
	 * 
	 * @param offset
	 * @return
	 */
	private IpLocation getIpLocation(long offset) {
		try {
			// 跳过4字节IP
			randomAccessFile.seek(offset + 4);
			// 读取第一个字节,判断是否是标识字节
			byte result = randomAccessFile.readByte();
			if (result == REDIRECT_MODE_ONE) {
				// 读取国家偏移量
				long countryOffset = ReadUtils.readLongByThree(
						randomAccessFile, bufferOne);
				// 跳转至偏移处
				randomAccessFile.seek(countryOffset);
				// 再次检查标识符
				result = randomAccessFile.readByte();
				if (result == REDIRECT_MODE_TWO) {
					ipLocation.setCountry(ReadUtils.readString(
							randomAccessFile, ReadUtils.readLongByThree(
									randomAccessFile, bufferOne), buffer));
					randomAccessFile.seek(countryOffset + 4);
				} else {
					ipLocation.setCountry(ReadUtils.readString(
							randomAccessFile, countryOffset, buffer));
				}
				// 读取地区标识符
				ipLocation.setArea(this.readArea(randomAccessFile
						.getFilePointer()));
			} else if (result == REDIRECT_MODE_TWO) {
				ipLocation.setCountry(ReadUtils.readString(randomAccessFile,
						ReadUtils.readLongByThree(randomAccessFile, bufferOne),
						buffer));
				ipLocation.setArea(this.readArea(offset + 8));
			} else {
				ipLocation.setCountry(ReadUtils.readString(randomAccessFile,
						randomAccessFile.getFilePointer() - 1, buffer));
				ipLocation.setArea(this.readArea(randomAccessFile
						.getFilePointer()));
			}
			return ipLocation;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 根据IP地区偏移量,获取IP信息
	 * 
	 * @param offset
	 * @return
	 */
	private IpLocation getIpLocation(int offset) {
		// 跳过4字节IP
		mappedByteBuffer.position(offset + 4);
		// 读取第一个字节,判断是否是标识字符
		byte result = mappedByteBuffer.get();
		if (result == REDIRECT_MODE_ONE) {
			// 读取国家偏移量
			int countryOffset = ReadUtils.readIntByThree(mappedByteBuffer);
			// 跳转至偏移处
			mappedByteBuffer.position(countryOffset);
			// 再次检查标识符
			result = mappedByteBuffer.get();
			if (result == REDIRECT_MODE_TWO) {
				ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
						ReadUtils.readIntByThree(mappedByteBuffer), buffer));
				mappedByteBuffer.position(countryOffset + 4);
			} else {
				ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
						countryOffset, buffer));
			}
			// 设置地区标识
			ipLocation.setArea(this.readArea(mappedByteBuffer.position()));
		} else if (result == REDIRECT_MODE_TWO) {
			ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
					ReadUtils.readIntByThree(mappedByteBuffer), buffer));
			ipLocation.setArea(this.readArea(offset + 8));
		} else {
			ipLocation.setCountry(ReadUtils.readString(mappedByteBuffer,
					mappedByteBuffer.position() - 1, buffer));
			ipLocation.setArea(this.readArea(mappedByteBuffer.position()));
		}
		return ipLocation;
	}

	/**
	 * 获取国家名称字符串
	 * 
	 * @return
	 */
	public String getCountry(String ip) {
		return this.getCountry(ConvertUtils.getIpArray(ip));
	}

	/**
	 * 获取国家地区
	 * 
	 * @param ip
	 * @return
	 */
	public String getCountry(byte[] ip) {
		// 检测IP地址文件是否正常
		if (randomAccessFile == null) {
			return Message.BAD_IP_FILE;
		}
		// 保存IP,转IP字节数组为字符串
		String ipStr = ConvertUtils.getIpString(ip);
		// 先从cache中检查ip,若没有在检测文件
		if (cache.containsKey(ipStr)) {
			IpLocation ipLocation = cache.get(ipStr);
			return ipLocation.getCountry();
		} else {
			IpLocation ipLocation = this.getIpLocation(ip);
			cache.put(ipStr, ipLocation.getCopy());
			return ipLocation.getCountry();
		}
	}

	/**
	 * 根据IP搜索IP文件
	 * 
	 * @param ip
	 * @return
	 */
	public IpLocation getIpLocation(byte[] ip) {
		IpLocation location = null;
		long offset = this.getLocateIp(ip);
		if (offset != -1) {
			location = this.getIpLocation(offset);
		}
		if (location == null) {
			location = new IpLocation();
			location.setCountry(Message.UNKNOW_COUNTRY);
			location.setArea(Message.UNKNOW_AREA);
		}
		return location;
	}

	/**
	 * 根据IP内容,定位IP地址所在的国家,返回一个偏移量
	 * 
	 * @param ip
	 * @return
	 */
	public long getLocateIp(byte[] ip) {
		long m = 0;
		int n;
		ReadUtils.readIp(randomAccessFile, begin, bufferTwo);
		n = ReadUtils.compareIp(ip, bufferTwo);
		if (n == 0)
			return begin;
		else if (n < 0)
			return -1;

		// 二分查找法查找IP
		for (long i = begin, j = end; i < j;) {
			m = this.getMiddleOffset(i, j);
			ReadUtils.readIp(randomAccessFile, m, bufferTwo);
			n = ReadUtils.compareIp(ip, bufferTwo);
			if (n > 0) {
				i = m;
			} else if (n < 0) {
				if (m == j) {
					j -= IP_RECORD_LENGTH;
					m = j;
				} else {
					j = m;
				}
			} else {
				return ReadUtils.readLongByThree(randomAccessFile, m + 4,
						bufferOne);
			}
		}
		m = ReadUtils.readLongByThree(randomAccessFile, m + 4, bufferOne);
		ReadUtils.readIp(randomAccessFile, m, bufferTwo);
		n = ReadUtils.compareIp(ip, bufferTwo);
		if (n <= 0)
			return m;
		else
			return -1;

	}

	/**
	 * 根据IP字节数组获取地区名称
	 * 
	 * @param ip
	 * @return
	 */
	private String getArea(byte[] ip) {
		// 检查IP文件是否正常
		if (randomAccessFile == null)
			return Message.BAD_IP_FILE;
		// 保存IP,转换字节数组IP为字符串
		String ipStr = ConvertUtils.getIpString(ip);
		// 现在cache中搜索结果,若没有,再从文件中查找
		if (cache.containsKey(ipStr)) {
			IpLocation location = cache.get(ipStr);
			return location.getArea();
		} else {
			IpLocation location = this.getIpLocation(ip);
			cache.put(ipStr, location.getCopy());
			return location.getArea();
		}
	}

	/**
	 * 根据IP获取地区名称
	 * 
	 * @param ip
	 * @return
	 */
	private String getArea(String ip) {
		return this.getArea(ConvertUtils.getIpArray(ip));
	}

	/**
	 * 从offset位置读取地区信息
	 * 
	 * @param offset
	 * @return
	 */
	private String readArea(long offset) {
		try {
			randomAccessFile.seek(offset);
			byte result = randomAccessFile.readByte();
			if (result == REDIRECT_MODE_ONE || result == REDIRECT_MODE_TWO) {
				long areaOffset = ReadUtils.readLongByThree(randomAccessFile,
						offset + 1, bufferOne);
				if (areaOffset == 0)
					return Message.UNKNOW_AREA;
				else
					return ReadUtils.readString(randomAccessFile, areaOffset,
							buffer);

			} else {
				return ReadUtils.readString(randomAccessFile, offset, buffer);
			}
		} catch (Exception e) {
			e.printStackTrace(); 
		}
		return "";
	}

	private String readArea(int offset) {
		mappedByteBuffer.position(offset);
		byte result = mappedByteBuffer.get();
		if (result == REDIRECT_MODE_ONE || result == REDIRECT_MODE_TWO) {
			int areaOffset = ReadUtils.readIntByThree(mappedByteBuffer);
			if (areaOffset == 0)
				return Message.UNKNOW_AREA;
			else
				return ReadUtils.readString(mappedByteBuffer, areaOffset,
						buffer);
		} else {
			return ReadUtils.readString(mappedByteBuffer, offset, buffer);
		}
	}

	/**
	 * 获取begin和end中间偏移量
	 * 
	 * @param begin
	 * @param end
	 * @return
	 */
	private long getMiddleOffset(long begin, long end) {
		long middle = (end - begin) / IP_RECORD_LENGTH;
		middle >>= 1;
		if (middle == 0)
			middle = 1;
		return begin + middle * IP_RECORD_LENGTH;
	}

}

7.测试程序

package com.test.ip;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

import com.test.ip.viewer.IpViewer;

public class Test {
	public static void main(String[] args){
		String ip = "63.251.90.8";
		IpViewer ipViewer = new IpViewer();
		System.out.println(ipViewer.getIpLocation(ip).getCountry()+":"+ipViewer.getIpLocation(ip).getArea());
	}
}  

你可能感兴趣的:(移动开发)