`
xiexd
  • 浏览: 244730 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java 读取纯真IP数据库QQwry.dat的源代码(转)

    博客分类:
  • JAVA
阅读更多
  1. java读取纯真IP数据库QQwry.dat的源代码,要运行此程序必须到网上下载QQwry.da,由于太大,我这里就不提供了。  
  2. 一、IPEntry.java  
  3. /** *  
  4. * 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP *  
  5.  
  6.  *   
  7.  * @author   
  8.  */   
  9. public   class  IPEntry {  
  10.     public  String beginIp;  
  11.     public  String endIp;  
  12.     public  String country;  
  13.     public  String area;  
  14.       
  15.     /**  
  16.      * 构造函数  
  17.      */   
  18.      
  19.   
  20.  public  IPEntry() {  
  21.         beginIp = endIp = country = area = "" ;  
  22.     }  
  23.       
  24.     public  String toString(){  
  25.     retur        this .area+ "  " + this .country+ "IP范围:" + this .beginIp+ "-" + this .endIp;  
  26.     }  
  27.    }   
  28.   
  29. 二、Utils.java  
  30.   
  31. /*  
  32.  * Created on 2004-8-4  
  33.  *  
  34.  */   
  35. import  java.io.UnsupportedEncodingException;  
  36. /**  
  37.  * @author LJ-silver  
  38.  */   
  39. public   class  Utils {  
  40.     /**  
  41.      * 从ip的字符串形式得到字节数组形式  
  42.      * @param ip 字符串形式的ip  
  43.      * @return 字节数组形式的ip  
  44.      */   
  45.     public   static   byte [] getIpByteArrayFromString(String ip) {  
  46.         byte [] ret =  new   byte [ 4 ];  
  47.         java.util.StringTokenizer st = new  java.util.StringTokenizer(ip,  "." );  
  48.         try  {  
  49.             ret[0 ] = ( byte )(Integer.parseInt(st.nextToken()) &  0xFF );  
  50.             ret[1 ] = ( byte )(Integer.parseInt(st.nextToken()) &  0xFF );  
  51.             ret[2 ] = ( byte )(Integer.parseInt(st.nextToken()) &  0xFF );  
  52.             ret[3 ] = ( byte )(Integer.parseInt(st.nextToken()) &  0xFF );  
  53.         } catch  (Exception e) {  
  54.             System.out.println(e.getMessage());  
  55.         }  
  56.         return  ret;  
  57.     }  
  58.       
  59.     public   static   void  main(String args[]){  
  60.          byte [] a=getIpByteArrayFromString(args[ 0 ]);  
  61.           for ( int  i= 0 ;i< a.length;i++)  
  62.                 System.out.println(a[i]);  
  63.           System.out.println(getIpStringFromBytes(a));   
  64.     }  
  65.     /**  
  66.      * 对原始字符串进行编码转换,如果失败,返回原始的字符串  
  67.      * @param s 原始字符串  
  68.      * @param srcEncoding 源编码方式  
  69.      * @param destEncoding 目标编码方式  
  70.      * @return 转换编码后的字符串,失败返回原始字符串  
  71.      */   
  72.     public   static  String getString(String s, String srcEncoding, String destEncoding) {  
  73.         try  {  
  74.             return   new  String(s.getBytes(srcEncoding), destEncoding);  
  75.         } catch  (UnsupportedEncodingException e) {  
  76.             return  s;  
  77.         }  
  78.     }  
  79.       
  80.     /**  
  81.      * 根据某种编码方式将字节数组转换成字符串  
  82.      * @param b 字节数组  
  83.      * @param encoding 编码方式  
  84.      * @return 如果encoding不支持,返回一个缺省编码的字符串  
  85.      */   
  86.     public   static  String getString( byte [] b, String encoding) {  
  87.         try  {  
  88.             return   new  String(b, encoding);  
  89.         } catch  (UnsupportedEncodingException e) {  
  90.             return   new  String(b);  
  91.         }  
  92.     }  
  93.       
  94.     /**  
  95.      * 根据某种编码方式将字节数组转换成字符串  
  96.      * @param b 字节数组  
  97.      * @param offset 要转换的起始位置  
  98.      * @param len 要转换的长度  
  99.      * @param encoding 编码方式  
  100.      * @return 如果encoding不支持,返回一个缺省编码的字符串  
  101.      */   
  102.     public   static  String getString( byte [] b,  int  offset,  int  len, String encoding) {  
  103.         try  {  
  104.             return   new  String(b, offset, len, encoding);  
  105.         } catch  (UnsupportedEncodingException e) {  
  106.             return   new  String(b, offset, len);  
  107.         }  
  108.     }  
  109.       
  110.     /**  
  111.      * @param ip ip的字节数组形式  
  112.      * @return 字符串形式的ip  
  113.      */   
  114.     public   static  String getIpStringFromBytes( byte [] ip) {  
  115.         StringBuffer sb = new  StringBuffer();  
  116.         sb.append(ip[0 ] &  0xFF );  
  117.         sb.append('.' );       
  118.         sb.append(ip[1 ] &  0xFF );  
  119.         sb.append('.' );       
  120.         sb.append(ip[2 ] &  0xFF );  
  121.         sb.append('.' );       
  122.         sb.append(ip[3 ] &  0xFF );  
  123.         return  sb.toString();  
  124.     }  
  125. }   
  126.   
  127.  三、IPSeeker.java  
  128.   
  129. /*  
  130. * LumaQQ - Java QQ Client  
  131. *  
  132. * Copyright (C) 2004 luma < stubma@163.com>  
  133. *  
  134. * This program is free software; you can redistribute it and/or modify  
  135. * it under the terms of the GNU General Public License as published by  
  136. * the Free Software Foundation; either version 2 of the License, or  
  137. * (at your option) any later version.  
  138. *  
  139. * This program is distributed in the hope that it will be useful,  
  140. * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  141. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
  142. * GNU General Public License for more details.  
  143. *  
  144. * You should have received a copy of the GNU General Public License  
  145. * along with this program; if not, write to the Free Software  
  146. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  
  147. */   
  148. import  java.io.FileNotFoundException;  
  149. import  java.io.IOException;  
  150. import  java.io.RandomAccessFile;  
  151. import  java.nio.ByteOrder;  
  152. import  java.nio.MappedByteBuffer;  
  153. import  java.nio.channels.FileChannel;  
  154. import  java.util.ArrayList;  
  155. import  java.util.Hashtable;  
  156. import  java.util.List;  
  157. /**  
  158.  *   
  159.  
  160.  * 用来读取QQwry.dat文件,以根据ip获得好友位置,QQwry.dat的格式是  
  161.  * 一. 文件头,共8字节  
  162.  *     1. 第一个起始IP的绝对偏移, 4字节  
  163.  *     2. 最后一个起始IP的绝对偏移, 4字节  
  164.  * 二. "结束地址/国家/区域"记录区  
  165.  *     四字节ip地址后跟的每一条记录分成两个部分  
  166.  *     1. 国家记录  
  167.  *     2. 地区记录  
  168.  *     但是地区记录是不一定有的。而且国家记录和地区记录都有两种形式  
  169.  *     1. 以0结束的字符串  
  170.  *     2. 4个字节,一个字节可能为0x1或0x2  
  171.  *        a. 为0x1时,表示在绝对偏移后还跟着一个区域的记录,注意是绝对偏移之后,而不是这四个字节之后  
  172.  *        b. 为0x2时,表示在绝对偏移后没有区域记录  
  173.  *        不管为0x1还是0x2,后三个字节都是实际国家名的文件内绝对偏移  
  174.  *        如果是地区记录,0x1和0x2的含义不明,但是如果出现这两个字节,也肯定是跟着3个字节偏移,如果不是  
  175.  *        则为0结尾字符串  
  176.  * 三. "起始地址/结束地址偏移"记录区  
  177.  *     1. 每条记录7字节,按照起始地址从小到大排列  
  178.  *        a. 起始IP地址,4字节  
  179.  *        b. 结束ip地址的绝对偏移,3字节  
  180.  *  
  181.  * 注意,这个文件里的ip地址和所有的偏移量均采用little-endian格式,而java是采用  
  182.  * big-endian格式的,要注意转换  
  183.  *   
  184.  
  185.  
  186.  *  
  187.  * @author 马若劼  
  188.  */   
  189. public   class  IPSeeker {  
  190.     /**  
  191.      *   
  192.  
  193.      * 用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区  
  194.      *   
  195.  
  196.  
  197.      *  
  198.      * @author 马若劼  
  199.      */   
  200.     private   class  IPLocation {  
  201.         public  String country;  
  202.         public  String area;  
  203.         public  IPLocation() {  
  204.             country = area = "" ;  
  205.         }  
  206.         public  IPLocation getCopy() {  
  207.             IPLocation ret = new  IPLocation();  
  208.             ret.country = country;  
  209.             ret.area = area;  
  210.             return  ret;  
  211.         }  
  212.     }  
  213.     private   static   final  String IP_FILE = IPSeeker. class .getResource( "/QQWry.dat" ).toString().substring( 5 );  
  214.     // 一些固定常量,比如记录长度等等   
  215.     private   static   final   int  IP_RECORD_LENGTH =  7 ;  
  216.     private   static   final   byte  AREA_FOLLOWED =  0x01 ;  
  217.     private   static   final   byte  NO_AREA =  0x2 ;  
  218.     // 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找   
  219.     private  Hashtable ipCache;  
  220.     // 随机文件访问类   
  221.     private  RandomAccessFile ipFile;  
  222.     // 内存映射文件   
  223.     private  MappedByteBuffer mbb;  
  224.     // 单一模式实例   
  225.     private   static  IPSeeker instance =  new  IPSeeker();  
  226.     // 起始地区的开始和结束的绝对偏移   
  227.     private   long  ipBegin, ipEnd;  
  228.     // 为提高效率而采用的临时变量   
  229.     private  IPLocation loc;  
  230.     private   byte [] buf;  
  231.     private   byte [] b4;  
  232.     private   byte [] b3;  
  233.     /**  
  234.      * 私有构造函数  
  235.      */   
  236.     private  IPSeeker()  {  
  237.         ipCache = new  Hashtable();  
  238.         loc = new  IPLocation();  
  239.         buf = new   byte [ 100 ];  
  240.         b4 = new   byte [ 4 ];  
  241.         b3 = new   byte [ 3 ];  
  242.         try  {  
  243.             ipFile = new  RandomAccessFile(IP_FILE,  "r" );  
  244.         } catch  (FileNotFoundException e) {  
  245.                         System.out.println(IPSeeker.class .getResource( "/QQWry.dat" ).toString());  
  246.                         System.out.println(IP_FILE);  
  247.             System.out.println("IP地址信息文件没有找到,IP显示功能将无法使用" );  
  248.             ipFile = null ;  
  249.         }  
  250.         // 如果打开文件成功,读取文件头信息   
  251.         if (ipFile !=  null ) {  
  252.             try  {  
  253.                 ipBegin = readLong4(0 );  
  254.                 ipEnd = readLong4(4 );  
  255.                 if (ipBegin == - 1  || ipEnd == - 1 ) {  
  256.                     ipFile.close();  
  257.                     ipFile = null ;  
  258.                 }  
  259.             } catch  (IOException e) {  
  260.                 System.out.println("IP地址信息文件格式有错误,IP显示功能将无法使用" );  
  261.                 ipFile = null ;  
  262.             }  
  263.         }  
  264.     }  
  265.     /**  
  266.      * @return 单一实例  
  267.      */   
  268.     public   static  IPSeeker getInstance() {  
  269.         return  instance;  
  270.     }  
  271.     /**  
  272.      * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录  
  273.      * @param s 地点子串  
  274.      * @return 包含IPEntry类型的List  
  275.      */   
  276.     public  List getIPEntriesDebug(String s) {  
  277.         List ret = new  ArrayList();  
  278.         long  endOffset = ipEnd +  4 ;  
  279.         for ( long  offset = ipBegin +  4 ; offset <= endOffset; offset += IP_RECORD_LENGTH) {  
  280.             // 读取结束IP偏移   
  281.             long  temp = readLong3(offset);  
  282.             // 如果temp不等于-1,读取IP的地点信息   
  283.             if (temp != - 1 ) {  
  284.                 IPLocation loc = getIPLocation(temp);  
  285.                 // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续   
  286.                 if (loc.country.indexOf(s) != - 1  || loc.area.indexOf(s) != - 1 ) {  
  287.                     IPEntry entry = new  IPEntry();  
  288.                     entry.country = loc.country;  
  289.                     entry.area = loc.area;  
  290.                     // 得到起始IP   
  291.                     readIP(offset - 4 , b4);  
  292.                     entry.beginIp = Utils.getIpStringFromBytes(b4);  
  293.                     // 得到结束IP   
  294.                     readIP(temp, b4);  
  295.                     entry.endIp = Utils.getIpStringFromBytes(b4);  
  296.                     // 添加该记录   
  297.                     ret.add(entry);  
  298.                 }  
  299.             }  
  300.         }  
  301.         return  ret;  
  302.     }  
  303.     /**  
  304.      * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录  
  305.      * @param s 地点子串  
  306.      * @return 包含IPEntry类型的List  
  307.      */   
  308.     public  List getIPEntries(String s) {  
  309.         List ret = new  ArrayList();  
  310.         try  {  
  311.             // 映射IP信息文件到内存中   
  312.             if (mbb ==  null ) {  
  313.                 FileChannel fc = ipFile.getChannel();  
  314.                 mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0 , ipFile.length());  
  315.                 mbb.order(ByteOrder.LITTLE_ENDIAN);  
  316.             }  
  317.             int  endOffset = ( int )ipEnd;  
  318.             for ( int  offset = ( int )ipBegin +  4 ; offset <= endOffset; offset += IP_RECORD_LENGTH) {  
  319.                 int  temp = readInt3(offset);  
  320.                 if (temp != - 1 ) {  
  321.                     IPLocation loc = getIPLocation(temp);  
  322.                     // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续   
  323.                     if (loc.country.indexOf(s) != - 1  || loc.area.indexOf(s) != - 1 ) {  
  324.                         IPEntry entry = new  IPEntry();  
  325.                         entry.country = loc.country;  
  326.                         entry.area = loc.area;  
  327.                         // 得到起始IP   
  328.                         readIP(offset - 4 , b4);  
  329.                         entry.beginIp = Utils.getIpStringFromBytes(b4);  
  330.                         // 得到结束IP   
  331.                         readIP(temp, b4);  
  332.                         entry.endIp = Utils.getIpStringFromBytes(b4);  
  333.                         // 添加该记录   
  334.                         ret.add(entry);  
  335.                     }  
  336.                 }  
  337.             }  
  338.         } catch  (IOException e) {  
  339.             System.out.println(e.getMessage());  
  340.         }  
  341.         return  ret;  
  342.     }  
  343.     /**  
  344.      * 从内存映射文件的offset位置开始的3个字节读取一个int  
  345.      * @param offset  
  346.      * @return  
  347.      */   
  348.     private   int  readInt3( int  offset) {  
  349.         mbb.position(offset);  
  350.         return  mbb.getInt() &  0x00FFFFFF ;  
  351.     }  
  352.     /**  
  353.      * 从内存映射文件的当前位置开始的3个字节读取一个int  
  354.      * @return  
  355.      */   
  356.     private   int  readInt3() {  
  357.         return  mbb.getInt() &  0x00FFFFFF ;  
  358.     }  
  359.     /**  
  360.      * 根据IP得到国家名  
  361.      * @param ip ip的字节数组形式  
  362.      * @return 国家名字符串  
  363.      */   
  364.     public  String getCountry( byte [] ip) {  
  365.         // 检查ip地址文件是否正常   
  366.         if (ipFile ==  null return   "错误的IP数据库文件" ;  
  367.         // 保存ip,转换ip字节数组为字符串形式   
  368.         String ipStr = Utils.getIpStringFromBytes(ip);  
  369.         // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件   
  370.         if (ipCache.containsKey(ipStr)) {  
  371.             IPLocation loc = (IPLocation)ipCache.get(ipStr);  
  372.             return  loc.country;  
  373.         } else  {  
  374.             IPLocation loc = getIPLocation(ip);  
  375.             ipCache.put(ipStr, loc.getCopy());  
  376.             return  loc.country;  
  377.         }  
  378.     }  
  379.     /**  
  380.      * 根据IP得到国家名  
  381.      * @param ip IP的字符串形式  
  382.      * @return 国家名字符串  
  383.      */   
  384.     public  String getCountry(String ip) {  
  385.         return  getCountry(Utils.getIpByteArrayFromString(ip));  
  386.     }  
  387.     /**  
  388.      * 根据IP得到地区名  
  389.      * @param ip ip的字节数组形式  
  390.      * @return 地区名字符串  
  391.      */   
  392.     public  String getArea( byte [] ip) {  
  393.         // 检查ip地址文件是否正常   
  394.         if (ipFile ==  null return   "错误的IP数据库文件" ;  
  395.         // 保存ip,转换ip字节数组为字符串形式   
  396.         String ipStr = Utils.getIpStringFromBytes(ip);  
  397.         // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件   
  398.         if (ipCache.containsKey(ipStr)) {  
  399.             IPLocation loc = (IPLocation)ipCache.get(ipStr);  
  400.             return  loc.area;  
  401.         } else  {  
  402.             IPLocation loc = getIPLocation(ip);  
  403.             ipCache.put(ipStr, loc.getCopy());  
  404.             return  loc.area;  
  405.         }  
  406.     }  
  407.     /**  
  408.      * 根据IP得到地区名  
  409.      * @param ip IP的字符串形式  
  410.      * @return 地区名字符串  
  411.      */   
  412.     public  String getArea(String ip) {  
  413.         return  getArea(Utils.getIpByteArrayFromString(ip));  
  414.     }  
  415.     /**  
  416.      * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到  
  417.      * @param ip 要查询的IP  
  418.      * @return IPLocation结构  
  419.      */   
  420.     private  IPLocation getIPLocation( byte [] ip) {  
  421.         IPLocation info = null ;  
  422.         long  offset = locateIP(ip);  
  423.         if (offset != - 1 )  
  424.             info = getIPLocation(offset);  
  425.         if (info ==  null ) {  
  426.             info = new  IPLocation();  
  427.             info.country = "未知国家" ;  
  428.             info.area = "未知地区" ;  
  429.         }  
  430.         return  info;  
  431.     }  
  432.     /**  
  433.      * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法  
  434.      * 用了这么一个函数来做转换  
  435.      * @param offset  
  436.      * @return 读取的long值,返回-1表示读取文件失败  
  437.      */   
  438.     private   long  readLong4( long  offset) {  
  439.         long  ret =  0 ;  
  440.         try  {  
  441.             ipFile.seek(offset);  
  442.             ret |= (ipFile.readByte() & 0xFF );  
  443.             ret |= ((ipFile.readByte() << 8 ) &  0xFF00 );  
  444.             ret |= ((ipFile.readByte() << 16 ) &  0xFF0000 );  
  445.             ret |= ((ipFile.readByte() << 24 ) &  0xFF000000 );  
  446.             return  ret;  
  447.         } catch  (IOException e) {  
  448.             return  - 1 ;  
  449.         }  
  450.     }  
  451.     /**  
  452.      * 从offset位置读取3个字节为一个long,因为java为big-endian格式,所以没办法  
  453.      * 用了这么一个函数来做转换  
  454.      * @param offset  
  455.      * @return 读取的long值,返回-1表示读取文件失败  
  456.      */   
  457.     private   long  readLong3( long  offset) {  
  458.         long  ret =  0 ;  
  459.         try  {  
  460.             ipFile.seek(offset);  
  461.             ipFile.readFully(b3);  
  462.             ret |= (b3[0 ] &  0xFF );  
  463.             ret |= ((b3[1 ] <<  8 ) &  0xFF00 );  
  464.             ret |= ((b3[2 ] <<  16 ) &  0xFF0000 );  
  465.             return  ret;  
  466.         } catch  (IOException e) {  
  467.             return  - 1 ;  
  468.         }  
  469.     }  
  470.     /**  
  471.      * 从当前位置读取3个字节转换成long  
  472.      * @return  
  473.      */   
  474.     private   long  readLong3() {  
  475.         long  ret =  0 ;  
  476.         try  {  
  477.             ipFile.readFully(b3);  
  478.             ret |= (b3[0 ] &  0xFF );  
  479.             ret |= ((b3[1 ] <<  8 ) &  0xFF00 );  
  480.             ret |= ((b3[2 ] <<  16 ) &  0xFF0000 );  
  481.             return  ret;  
  482.         } catch  (IOException e) {  
  483.             return  - 1 ;  
  484.         }  
  485.     }  
  486.     /**  
  487.      * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是  
  488.      * 文件中是little-endian形式,将会进行转换  
  489.      * @param offset  
  490.      * @param ip  
  491.      */   
  492.     private   void  readIP( long  offset,  byte [] ip) {  
  493.         try  {  
  494.             ipFile.seek(offset);  
  495.             ipFile.readFully(ip);  
  496.             byte  temp = ip[ 0 ];  
  497.             ip[0 ] = ip[ 3 ];  
  498.             ip[3 ] = temp;  
  499.             temp = ip[1 ];  
  500.             ip[1 ] = ip[ 2 ];  
  501.             ip[2 ] = temp;  
  502.         } catch  (IOException e) {  
  503.             System.out.println(e.getMessage());  
  504.         }  
  505.     }  
  506.     /**  
  507.      * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是  
  508.      * 文件中是little-endian形式,将会进行转换  
  509.      * @param offset  
  510.      * @param ip  
  511.      */   
  512.     private   void  readIP( int  offset,  byte [] ip) {  
  513.         mbb.position(offset);  
  514.         mbb.get(ip);  
  515.         byte  temp = ip[ 0 ];  
  516.         ip[0 ] = ip[ 3 ];  
  517.         ip[3 ] = temp;  
  518.         temp = ip[1 ];  
  519.         ip[1 ] = ip[ 2 ];  
  520.         ip[2 ] = temp;  
  521.     }  
  522.     /**  
  523.      * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的  
  524.      * @param ip 要查询的IP  
  525.      * @param beginIp 和被查询IP相比较的IP  
  526.      * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。  
  527.      */   
  528.     private   int  compareIP( byte [] ip,  byte [] beginIp) {  
  529.         for ( int  i =  0 ; i <  4 ; i++) {  
  530.             int  r = compareByte(ip[i], beginIp[i]);  
  531.             if (r !=  0 )  
  532.                 return  r;  
  533.         }  
  534.         return   0 ;  
  535.     }  
  536.     /**  
  537.      * 把两个byte当作无符号数进行比较  
  538.      * @param b1  
  539.      * @param b2  
  540.      * @return 若b1大于b2则返回1,相等返回0,小于返回-1  
  541.      */   
  542.     private   int  compareByte( byte  b1,  byte  b2) {  
  543.         if ((b1 &  0xFF ) > (b2 &  0xFF ))  // 比较是否大于   
  544.             return   1 ;  
  545.         else   if ((b1 ^ b2) ==  0 ) // 判断是否相等   
  546.             return   0 ;  
  547.         else   
  548.             return
    分享到:
    评论

相关推荐

Global site tag (gtag.js) - Google Analytics