依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

【好消息,好消息,好消息】VIP会员可以发表文章赚积分啦 !
查看: 19|回复: 0

IPSeeker (用来读取QQwry.dat二进制文件)

[复制链接] 主动推送

1万

主题

1万

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
12008
发表于 7 天前 | 显示全部楼层 |阅读模式
IPSeeker (用来读取QQwry.dat二进制文件)
  1. package com.sxt.etl.util.ip;

  2. import java.io.FileNotFoundException;
  3. import java.io.IOException;
  4. import java.io.RandomAccessFile;
  5. import java.io.UnsupportedEncodingException;
  6. import java.nio.ByteOrder;
  7. import java.nio.MappedByteBuffer;
  8. import java.nio.channels.FileChannel;
  9. import java.util.ArrayList;
  10. import java.util.Hashtable;
  11. import java.util.List;

  12. /**
  13. * * 用来读取QQwry.dat文件,以根据ip获得好友位置,QQwry.dat的格式是 一. 文件头,共8字节 1. 第一个起始IP的绝对偏移, 4字节
  14. * 2. 最后一个起始IP的绝对偏移, 4字节 二. "结束地址/国家/区域"记录区 四字节ip地址后跟的每一条记录分成两个部分 1. 国家记录 2.
  15. * 地区记录 但是地区记录是不一定有的。而且国家记录和地区记录都有两种形式 1. 以0结束的字符串 2. 4个字节,一个字节可能为0x1或0x2 a.
  16. * 为0x1时,表示在绝对偏移后还跟着一个区域的记录,注意是绝对偏移之后,而不是这四个字节之后 b. 为0x2时,表示在绝对偏移后没有区域记录
  17. * 不管为0x1还是0x2,后三个字节都是实际国家名的文件内绝对偏移
  18. * 如果是地区记录,0x1和0x2的含义不明,但是如果出现这两个字节,也肯定是跟着3个字节偏移,如果不是 则为0结尾字符串 三.
  19. * "起始地址/结束地址偏移"记录区 1. 每条记录7字节,按照起始地址从小到大排列 a. 起始IP地址,4字节 b. 结束ip地址的绝对偏移,3字节
  20. *
  21. * 注意,这个文件里的ip地址和所有的偏移量均采用little-endian格式,而java是采用 big-endian格式的,要注意转换
  22. *
  23. * @author root
  24. */
  25. public class IPSeeker {
  26.    
  27.     // 一些固定常量,比如记录长度等等
  28.     private static final int IP_RECORD_LENGTH = 7;
  29.     private static final byte AREA_FOLLOWED = 0x01;
  30.     private static final byte NO_AREA = 0x2;

  31.     // 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找
  32.     private Hashtable ipCache;
  33.     // 随机文件访问类
  34.     private RandomAccessFile ipFile;
  35.     // 内存映射文件
  36.     private MappedByteBuffer mbb;
  37.     // 单一模式实例
  38.     private static IPSeeker instance = null;
  39.     // 起始地区的开始和结束的绝对偏移
  40.     private long ipBegin, ipEnd;
  41.     // 为提高效率而采用的临时变量
  42.     private IPLocation loc;
  43.     private byte[] buf;
  44.     private byte[] b4;
  45.     private byte[] b3;

  46.     /** */
  47.     /**
  48.      * 私有构造函数
  49.      */
  50.     protected IPSeeker() {
  51.         ipCache = new Hashtable();
  52.         loc = new IPLocation();
  53.         buf = new byte[100];
  54.         b4 = new byte[4];
  55.         b3 = new byte[3];
  56.         try {
  57.             String ipFilePath = IPSeeker.class.getResource("/qqwry.dat")
  58.                     .getFile();
  59.             ipFile = new RandomAccessFile(ipFilePath, "r");
  60.         } catch (FileNotFoundException e) {
  61.             System.out.println("IP地址信息文件没有找到,IP显示功能将无法使用");
  62.             ipFile = null;

  63.         }
  64.         // 如果打开文件成功,读取文件头信息
  65.         if (ipFile != null) {
  66.             try {
  67.                 ipBegin = readLong4(0);
  68.                 ipEnd = readLong4(4);
  69.                 if (ipBegin == -1 || ipEnd == -1) {
  70.                     ipFile.close();
  71.                     ipFile = null;
  72.                 }
  73.             } catch (IOException e) {
  74.                 System.out.println("IP地址信息文件格式有错误,IP显示功能将无法使用");
  75.                 ipFile = null;
  76.             }
  77.         }
  78.     }

  79.     /** */
  80.     /**
  81.      * @return 单一实例
  82.      */
  83.     public static IPSeeker getInstance() {
  84.         if (instance == null) {
  85.             instance = new IPSeeker();
  86.         }
  87.         return instance;
  88.     }

  89.     /** */
  90.     /**
  91.      * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
  92.      *
  93.      * @param s
  94.      *            地点子串
  95.      * @return 包含IPEntry类型的List
  96.      */
  97.     public List getIPEntriesDebug(String s) {
  98.         List ret = new ArrayList();
  99.         long endOffset = ipEnd + 4;
  100.         for (long offset = ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
  101.             // 读取结束IP偏移
  102.             long temp = readLong3(offset);
  103.             // 如果temp不等于-1,读取IP的地点信息
  104.             if (temp != -1) {
  105.                 IPLocation loc = getIPLocation(temp);
  106.                 // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
  107.                 if (loc.country.indexOf(s) != -1 || loc.area.indexOf(s) != -1) {
  108.                     IPEntry entry = new IPEntry();
  109.                     entry.country = loc.country;
  110.                     entry.area = loc.area;
  111.                     // 得到起始IP
  112.                     readIP(offset - 4, b4);
  113.                     entry.beginIp = IPSeekerUtils.getIpStringFromBytes(b4);
  114.                     // 得到结束IP
  115.                     readIP(temp, b4);
  116.                     entry.endIp = IPSeekerUtils.getIpStringFromBytes(b4);
  117.                     // 添加该记录
  118.                     ret.add(entry);
  119.                 }
  120.             }
  121.         }
  122.         return ret;
  123.     }

  124.     /** */
  125.     /**
  126.      * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
  127.      *
  128.      * @param s
  129.      *            地点子串
  130.      * @return 包含IPEntry类型的List
  131.      */
  132.     public List getIPEntries(String s) {
  133.         List ret = new ArrayList();
  134.         try {
  135.             // 映射IP信息文件到内存中
  136.             if (mbb == null) {
  137.                 FileChannel fc = ipFile.getChannel();
  138.                 mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());
  139.                 mbb.order(ByteOrder.LITTLE_ENDIAN);
  140.             }

  141.             int endOffset = (int) ipEnd;
  142.             for (int offset = (int) ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
  143.                 int temp = readInt3(offset);
  144.                 if (temp != -1) {
  145.                     IPLocation loc = getIPLocation(temp);
  146.                     // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
  147.                     if (loc.country.indexOf(s) != -1
  148.                             || loc.area.indexOf(s) != -1) {
  149.                         IPEntry entry = new IPEntry();
  150.                         entry.country = loc.country;
  151.                         entry.area = loc.area;
  152.                         // 得到起始IP
  153.                         readIP(offset - 4, b4);
  154.                         entry.beginIp = IPSeekerUtils.getIpStringFromBytes(b4);
  155.                         // 得到结束IP
  156.                         readIP(temp, b4);
  157.                         entry.endIp = IPSeekerUtils.getIpStringFromBytes(b4);
  158.                         // 添加该记录
  159.                         ret.add(entry);
  160.                     }
  161.                 }
  162.             }
  163.         } catch (IOException e) {
  164.             System.out.println(e.getMessage());
  165.         }
  166.         return ret;
  167.     }

  168.     /** */
  169.     /**
  170.      * 从内存映射文件的offset位置开始的3个字节读取一个int
  171.      *
  172.      * @param offset
  173.      * @return
  174.      */
  175.     private int readInt3(int offset) {
  176.         mbb.position(offset);
  177.         return mbb.getInt() & 0x00FFFFFF;
  178.     }

  179.     /** */
  180.     /**
  181.      * 从内存映射文件的当前位置开始的3个字节读取一个int
  182.      *
  183.      * @return
  184.      */
  185.     private int readInt3() {
  186.         return mbb.getInt() & 0x00FFFFFF;
  187.     }

  188.     /** */
  189.     /**
  190.      * 根据IP得到国家名
  191.      *
  192.      * @param ip
  193.      *            ip的字节数组形式
  194.      * @return 国家名字符串
  195.      */
  196.     public String getCountry(byte[] ip) {
  197.         // 检查ip地址文件是否正常
  198.         if (ipFile == null)
  199.             return "错误的IP数据库文件";
  200.         // 保存ip,转换ip字节数组为字符串形式
  201.         String ipStr = IPSeekerUtils.getIpStringFromBytes(ip);
  202.         // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
  203.         if (ipCache.containsKey(ipStr)) {
  204.             IPLocation loc = (IPLocation) ipCache.get(ipStr);
  205.             return loc.country;
  206.         } else {
  207.             IPLocation loc = getIPLocation(ip);
  208.             ipCache.put(ipStr, loc.getCopy());
  209.             return loc.country;
  210.         }
  211.     }

  212.     /** */
  213.     /**
  214.      * 根据IP得到国家名
  215.      *
  216.      * @param ip
  217.      *            IP的字符串形式
  218.      * @return 国家名字符串
  219.      */
  220.     public String getCountry(String ip) {
  221.         return getCountry(IPSeekerUtils.getIpByteArrayFromString(ip));
  222.     }

  223.     /** */
  224.     /**
  225.      * 根据IP得到地区名
  226.      *
  227.      * @param ip
  228.      *            ip的字节数组形式
  229.      * @return 地区名字符串
  230.      */
  231.     public String getArea(byte[] ip) {
  232.         // 检查ip地址文件是否正常
  233.         if (ipFile == null)
  234.             return "错误的IP数据库文件";
  235.         // 保存ip,转换ip字节数组为字符串形式
  236.         String ipStr = IPSeekerUtils.getIpStringFromBytes(ip);
  237.         // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
  238.         if (ipCache.containsKey(ipStr)) {
  239.             IPLocation loc = (IPLocation) ipCache.get(ipStr);
  240.             return loc.area;
  241.         } else {
  242.             IPLocation loc = getIPLocation(ip);
  243.             ipCache.put(ipStr, loc.getCopy());
  244.             return loc.area;
  245.         }
  246.     }

  247.     /**
  248.      * 根据IP得到地区名
  249.      *
  250.      * @param ip
  251.      *            IP的字符串形式
  252.      * @return 地区名字符串
  253.      */
  254.     public String getArea(String ip) {
  255.         return getArea(IPSeekerUtils.getIpByteArrayFromString(ip));
  256.     }

  257.     /** */
  258.     /**
  259.      * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到
  260.      *
  261.      * @param ip
  262.      *            要查询的IP
  263.      * @return IPLocation结构
  264.      */
  265.     public IPLocation getIPLocation(byte[] ip) {
  266.         IPLocation info = null;
  267.         long offset = locateIP(ip);
  268.         if (offset != -1)
  269.             info = getIPLocation(offset);
  270.         if (info == null) {
  271.             info = new IPLocation();
  272.             info.country = "未知国家";
  273.             info.area = "未知地区";
  274.         }
  275.         return info;
  276.     }

  277.     /**
  278.      * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法 用了这么一个函数来做转换
  279.      *
  280.      * @param offset
  281.      * @return 读取的long值,返回-1表示读取文件失败
  282.      */
  283.     private long readLong4(long offset) {
  284.         long ret = 0;
  285.         try {
  286.             ipFile.seek(offset);
  287.             ret |= (ipFile.readByte() & 0xFF);
  288.             ret |= ((ipFile.readByte() << 8) & 0xFF00);
  289.             ret |= ((ipFile.readByte() << 16) & 0xFF0000);
  290.             ret |= ((ipFile.readByte() << 24) & 0xFF000000);
  291.             return ret;
  292.         } catch (IOException e) {
  293.             return -1;
  294.         }
  295.     }

  296.     /**
  297.      * 从offset位置读取3个字节为一个long,因为java为big-endian格式,所以没办法 用了这么一个函数来做转换
  298.      *
  299.      * @param offset
  300.      * @return 读取的long值,返回-1表示读取文件失败
  301.      */
  302.     private long readLong3(long offset) {
  303.         long ret = 0;
  304.         try {
  305.             ipFile.seek(offset);
  306.             ipFile.readFully(b3);
  307.             ret |= (b3[0] & 0xFF);
  308.             ret |= ((b3[1] << 8) & 0xFF00);
  309.             ret |= ((b3[2] << 16) & 0xFF0000);
  310.             return ret;
  311.         } catch (IOException e) {
  312.             return -1;
  313.         }
  314.     }

  315.     /**
  316.      * 从当前位置读取3个字节转换成long
  317.      *
  318.      * @return
  319.      */
  320.     private long readLong3() {
  321.         long ret = 0;
  322.         try {
  323.             ipFile.readFully(b3);
  324.             ret |= (b3[0] & 0xFF);
  325.             ret |= ((b3[1] << 8) & 0xFF00);
  326.             ret |= ((b3[2] << 16) & 0xFF0000);
  327.             return ret;
  328.         } catch (IOException e) {
  329.             return -1;
  330.         }
  331.     }

  332.     /**
  333.      * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
  334.      * 文件中是little-endian形式,将会进行转换
  335.      *
  336.      * @param offset
  337.      * @param ip
  338.      */
  339.     private void readIP(long offset, byte[] ip) {
  340.         try {
  341.             ipFile.seek(offset);
  342.             ipFile.readFully(ip);
  343.             byte temp = ip[0];
  344.             ip[0] = ip[3];
  345.             ip[3] = temp;
  346.             temp = ip[1];
  347.             ip[1] = ip[2];
  348.             ip[2] = temp;
  349.         } catch (IOException e) {
  350.             System.out.println(e.getMessage());
  351.         }
  352.     }

  353.     /**
  354.      * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
  355.      * 文件中是little-endian形式,将会进行转换
  356.      *
  357.      * @param offset
  358.      * @param ip
  359.      */
  360.     private void readIP(int offset, byte[] ip) {
  361.         mbb.position(offset);
  362.         mbb.get(ip);
  363.         byte temp = ip[0];
  364.         ip[0] = ip[3];
  365.         ip[3] = temp;
  366.         temp = ip[1];
  367.         ip[1] = ip[2];
  368.         ip[2] = temp;
  369.     }

  370.     /**
  371.      * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的
  372.      *
  373.      * @param ip
  374.      *            要查询的IP
  375.      * @param beginIp
  376.      *            和被查询IP相比较的IP
  377.      * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。
  378.      */
  379.     private int compareIP(byte[] ip, byte[] beginIp) {
  380.         for (int i = 0; i < 4; i++) {
  381.             int r = compareByte(ip[i], beginIp[i]);
  382.             if (r != 0)
  383.                 return r;
  384.         }
  385.         return 0;
  386.     }

  387.     /**
  388.      * 把两个byte当作无符号数进行比较
  389.      *
  390.      * @param b1
  391.      * @param b2
  392.      * @return 若b1大于b2则返回1,相等返回0,小于返回-1
  393.      */
  394.     private int compareByte(byte b1, byte b2) {
  395.         if ((b1 & 0xFF) > (b2 & 0xFF)) // 比较是否大于
  396.             return 1;
  397.         else if ((b1 ^ b2) == 0)// 判断是否相等
  398.             return 0;
  399.         else
  400.             return -1;
  401.     }

  402.     /**
  403.      * 这个方法将根据ip的内容,定位到包含这个ip国家地区的记录处,返回一个绝对偏移 方法使用二分法查找。
  404.      *
  405.      * @param ip
  406.      *            要查询的IP
  407.      * @return 如果找到了,返回结束IP的偏移,如果没有找到,返回-1
  408.      */
  409.     private long locateIP(byte[] ip) {
  410.         long m = 0;
  411.         int r;
  412.         // 比较第一个ip项
  413.         readIP(ipBegin, b4);
  414.         r = compareIP(ip, b4);
  415.         if (r == 0)
  416.             return ipBegin;
  417.         else if (r < 0)
  418.             return -1;
  419.         // 开始二分搜索
  420.         for (long i = ipBegin, j = ipEnd; i < j;) {
  421.             m = getMiddleOffset(i, j);
  422.             readIP(m, b4);
  423.             r = compareIP(ip, b4);
  424.             // log.debug(Utils.getIpStringFromBytes(b));
  425.             if (r > 0)
  426.                 i = m;
  427.             else if (r < 0) {
  428.                 if (m == j) {
  429.                     j -= IP_RECORD_LENGTH;
  430.                     m = j;
  431.                 } else
  432.                     j = m;
  433.             } else
  434.                 return readLong3(m + 4);
  435.         }
  436.         // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非
  437.         // 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移
  438.         m = readLong3(m + 4);
  439.         readIP(m, b4);
  440.         r = compareIP(ip, b4);
  441.         if (r <= 0)
  442.             return m;
  443.         else
  444.             return -1;
  445.     }

  446.     /**
  447.      * 得到begin偏移和end偏移中间位置记录的偏移
  448.      *
  449.      * @param begin
  450.      * @param end
  451.      * @return
  452.      */
  453.     private long getMiddleOffset(long begin, long end) {
  454.         long records = (end - begin) / IP_RECORD_LENGTH;
  455.         records >>= 1;
  456.         if (records == 0)
  457.             records = 1;
  458.         return begin + records * IP_RECORD_LENGTH;
  459.     }

  460.     /**
  461.      * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构
  462.      *
  463.      * @param offset
  464.      * @return
  465.      */
  466.     private IPLocation getIPLocation(long offset) {
  467.         try {
  468.             // 跳过4字节ip
  469.             ipFile.seek(offset + 4);
  470.             // 读取第一个字节判断是否标志字节
  471.             byte b = ipFile.readByte();
  472.             if (b == AREA_FOLLOWED) {
  473.                 // 读取国家偏移
  474.                 long countryOffset = readLong3();
  475.                 // 跳转至偏移处
  476.                 ipFile.seek(countryOffset);
  477.                 // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
  478.                 b = ipFile.readByte();
  479.                 if (b == NO_AREA) {
  480.                     loc.country = readString(readLong3());
  481.                     ipFile.seek(countryOffset + 4);
  482.                 } else
  483.                     loc.country = readString(countryOffset);
  484.                 // 读取地区标志
  485.                 loc.area = readArea(ipFile.getFilePointer());
  486.             } else if (b == NO_AREA) {
  487.                 loc.country = readString(readLong3());
  488.                 loc.area = readArea(offset + 8);
  489.             } else {
  490.                 loc.country = readString(ipFile.getFilePointer() - 1);
  491.                 loc.area = readArea(ipFile.getFilePointer());
  492.             }
  493.             return loc;
  494.         } catch (IOException e) {
  495.             return null;
  496.         }
  497.     }

  498.     /**
  499.      * @param offset
  500.      * @return
  501.      */
  502.     private IPLocation getIPLocation(int offset) {
  503.         // 跳过4字节ip
  504.         mbb.position(offset + 4);
  505.         // 读取第一个字节判断是否标志字节
  506.         byte b = mbb.get();
  507.         if (b == AREA_FOLLOWED) {
  508.             // 读取国家偏移
  509.             int countryOffset = readInt3();
  510.             // 跳转至偏移处
  511.             mbb.position(countryOffset);
  512.             // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
  513.             b = mbb.get();
  514.             if (b == NO_AREA) {
  515.                 loc.country = readString(readInt3());
  516.                 mbb.position(countryOffset + 4);
  517.             } else
  518.                 loc.country = readString(countryOffset);
  519.             // 读取地区标志
  520.             loc.area = readArea(mbb.position());
  521.         } else if (b == NO_AREA) {
  522.             loc.country = readString(readInt3());
  523.             loc.area = readArea(offset + 8);
  524.         } else {
  525.             loc.country = readString(mbb.position() - 1);
  526.             loc.area = readArea(mbb.position());
  527.         }
  528.         return loc;
  529.     }

  530.     /**
  531.      * 从offset偏移开始解析后面的字节,读出一个地区名
  532.      *
  533.      * @param offset
  534.      * @return 地区名字符串
  535.      * @throws IOException
  536.      */
  537.     private String readArea(long offset) throws IOException {
  538.         ipFile.seek(offset);
  539.         byte b = ipFile.readByte();
  540.         if (b == 0x01 || b == 0x02) {
  541.             long areaOffset = readLong3(offset + 1);
  542.             if (areaOffset == 0)
  543.                 return "未知地区";
  544.             else
  545.                 return readString(areaOffset);
  546.         } else
  547.             return readString(offset);
  548.     }

  549.     /**
  550.      * @param offset
  551.      * @return
  552.      */
  553.     private String readArea(int offset) {
  554.         mbb.position(offset);
  555.         byte b = mbb.get();
  556.         if (b == 0x01 || b == 0x02) {
  557.             int areaOffset = readInt3();
  558.             if (areaOffset == 0)
  559.                 return "未知地区";
  560.             else
  561.                 return readString(areaOffset);
  562.         } else
  563.             return readString(offset);
  564.     }

  565.     /**
  566.      * 从offset偏移处读取一个以0结束的字符串
  567.      *
  568.      * @param offset
  569.      * @return 读取的字符串,出错返回空字符串
  570.      */
  571.     private String readString(long offset) {
  572.         try {
  573.             ipFile.seek(offset);
  574.             int i;
  575.             for (i = 0, buf[i] = ipFile.readByte(); buf[i] != 0; buf[++i] = ipFile
  576.                     .readByte())
  577.                 ;
  578.             if (i != 0)
  579.                 return IPSeekerUtils.getString(buf, 0, i, "GBK");
  580.         } catch (IOException e) {
  581.             System.out.println(e.getMessage());
  582.         }
  583.         return "";
  584.     }

  585.     /**
  586.      * 从内存映射文件的offset位置得到一个0结尾字符串
  587.      *
  588.      * @param offset
  589.      * @return
  590.      */
  591.     private String readString(int offset) {
  592.         try {
  593.             mbb.position(offset);
  594.             int i;
  595.             for (i = 0, buf[i] = mbb.get(); buf[i] != 0; buf[++i] = mbb.get())
  596.                 ;
  597.             if (i != 0)
  598.                 return IPSeekerUtils.getString(buf, 0, i, "GBK");
  599.         } catch (IllegalArgumentException e) {
  600.             System.out.println(e.getMessage());
  601.         }
  602.         return "";
  603.     }

  604.     public String getAddress(String ip) {
  605.         String country = getCountry(ip).equals(" CZ88.NET") ? ""
  606.                 : getCountry(ip);
  607.         String area = getArea(ip).equals(" CZ88.NET") ? "" : getArea(ip);
  608.         String address = country + " " + area;
  609.         return address.trim();
  610.     }

  611.     /**
  612.      * * 用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区
  613.      *
  614.      *
  615.      * @author swallow
  616.      */
  617.     public class IPLocation {
  618.         public String country;
  619.         public String area;

  620.         public IPLocation() {
  621.             country = area = "";
  622.         }

  623.         public IPLocation getCopy() {
  624.             IPLocation ret = new IPLocation();
  625.             ret.country = country;
  626.             ret.area = area;
  627.             return ret;
  628.         }
  629.     }

  630.     /**
  631.      * 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP *
  632.      *
  633.      *
  634.      * @author root
  635.      */
  636.     public class IPEntry {
  637.         public String beginIp;
  638.         public String endIp;
  639.         public String country;
  640.         public String area;

  641.         public IPEntry() {
  642.             beginIp = endIp = country = area = "";
  643.         }

  644.         public String toString() {
  645.             return this.area + " " + this.country + "IP  Χ:" + this.beginIp
  646.                     + "-" + this.endIp;
  647.         }
  648.     }

  649.     /**
  650.      * 操作工具类
  651.      *
  652.      * @author root
  653.      *
  654.      */
  655.     public static class IPSeekerUtils {
  656.         /**
  657.          * 从ip的字符串形式得到字节数组形式
  658.          *
  659.          * @param ip
  660.          *            字符串形式的ip
  661.          * @return 字节数组形式的ip
  662.          */
  663.         public static byte[] getIpByteArrayFromString(String ip) {
  664.             byte[] ret = new byte[4];
  665.             java.util.StringTokenizer st = new java.util.StringTokenizer(ip,
  666.                     ".");
  667.             try {
  668.                 ret[0] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
  669.                 ret[1] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
  670.                 ret[2] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
  671.                 ret[3] = (byte) (Integer.parseInt(st.nextToken()) & 0xFF);
  672.             } catch (Exception e) {
  673.                 System.out.println(e.getMessage());
  674.             }
  675.             return ret;
  676.         }

  677.         /**
  678.          * 对原始字符串进行编码转换,如果失败,返回原始的字符串
  679.          *
  680.          * @param s
  681.          *            原始字符串
  682.          * @param srcEncoding
  683.          *            源编码方式
  684.          * @param destEncoding
  685.          *            目标编码方式
  686.          * @return 转换编码后的字符串,失败返回原始字符串
  687.          */
  688.         public static String getString(String s, String srcEncoding,
  689.                 String destEncoding) {
  690.             try {
  691.                 return new String(s.getBytes(srcEncoding), destEncoding);
  692.             } catch (UnsupportedEncodingException e) {
  693.                 return s;
  694.             }
  695.         }

  696.         /**
  697.          * 根据某种编码方式将字节数组转换成字符串
  698.          *
  699.          * @param b
  700.          *            字节数组
  701.          * @param encoding
  702.          *            编码方式
  703.          * @return 如果encoding不支持,返回一个缺省编码的字符串
  704.          */
  705.         public static String getString(byte[] b, String encoding) {
  706.             try {
  707.                 return new String(b, encoding);
  708.             } catch (UnsupportedEncodingException e) {
  709.                 return new String(b);
  710.             }
  711.         }

  712.         /**
  713.          * 根据某种编码方式将字节数组转换成字符串
  714.          *
  715.          * @param b
  716.          *            字节数组
  717.          * @param offset
  718.          *            要转换的起始位置
  719.          * @param len
  720.          *            要转换的长度
  721.          * @param encoding
  722.          *            编码方式
  723.          * @return 如果encoding不支持,返回一个缺省编码的字符串
  724.          */
  725.         public static String getString(byte[] b, int offset, int len,
  726.                 String encoding) {
  727.             try {
  728.                 return new String(b, offset, len, encoding);
  729.             } catch (UnsupportedEncodingException e) {
  730.                 return new String(b, offset, len);
  731.             }
  732.         }

  733.         /**
  734.          * @param ip
  735.          *            ip的字节数组形式
  736.          * @return 字符串形式的ip
  737.          */
  738.         public static String getIpStringFromBytes(byte[] ip) {
  739.             StringBuffer sb = new StringBuffer();
  740.             sb.append(ip[0] & 0xFF);
  741.             sb.append('.');
  742.             sb.append(ip[1] & 0xFF);
  743.             sb.append('.');
  744.             sb.append(ip[2] & 0xFF);
  745.             sb.append('.');
  746.             sb.append(ip[3] & 0xFF);
  747.             return sb.toString();
  748.         }
  749.     }

  750.     /**
  751.      * 获取全部ip地址集合列表
  752.      *
  753.      * @return
  754.      */
  755.     public List<String> getAllIp() {
  756.         List<String> list = new ArrayList<String>();
  757.         byte[] buf = new byte[4];
  758.         for (long i = ipBegin; i < ipEnd; i += IP_RECORD_LENGTH) {
  759.             try {
  760.                 this.readIP(this.readLong3(i + 4), buf); // 读取ip,最终ip放到buf中
  761.                 String ip = IPSeekerUtils.getIpStringFromBytes(buf);
  762.                 list.add(ip);
  763.             } catch (Exception e) {
  764.                 // nothing
  765.             }
  766.         }
  767.         return list;
  768.     }
  769. }
复制代码


相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|小黑屋|依星资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2024-11-23 23:12

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

快速回复 返回顶部 返回列表