纯真数据库理解及根据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<String, IpLocation> 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<String, IpLocation>();
        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<IpEntity> getIpEntityDebug(String str) {
        List<IpEntity> list = new ArrayList<IpEntity>();
        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<IpEntity> getIpEntity(String s) {

        List<IpEntity> list = new ArrayList<IpEntity>();
        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());
    }
}  


原文:https://blog.csdn.net/aleyns/article/details/78849835 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值