具体解析的纯真版IP地址库请详见 http://lumaqq.linuxsir.org/article/qqwry_format_detail.html ,这里就不多叙述了。 
看下JAVA代码中怎么解析IP的吧。 (代码参考至lumaQQ.谢谢开源作者luma)

解析的主类

Java代码 
  1. package com.showtime.IPparse;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.io.RandomAccessFile;
  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.HashMap;
  11. import java.util.List;
  12. import java.util.Map;
  13. import com.showtime.util.LogFactory;
  14. import org.apache.log4j.Level;
  15. public class IPSeeker {
  16. //纯真IP数据库名
  17. private String IP_FILE="QQWry.Dat";
  18. //保存的文件夹
  19. private String INSTALL_DIR="f:/qqwry";
  20. // 一些固定常量,比如记录长度等等
  21. private static final int IP_RECORD_LENGTH = 7;
  22. private static final byte REDIRECT_MODE_1 = 0x01;
  23. private static final byte REDIRECT_MODE_2 = 0x02;
  24. // 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找
  25. private Map<String, IPLocation> ipCache;
  26. // 随机文件访问类
  27. private RandomAccessFile ipFile;
  28. // 内存映射文件
  29. private MappedByteBuffer mbb;
  30. // 起始地区的开始和结束的绝对偏移
  31. private long ipBegin, ipEnd;
  32. // 为提高效率而采用的临时变量
  33. private IPLocation loc;
  34. private byte[] buf;
  35. private byte[] b4;
  36. private byte[] b3;
  37. public IPSeeker(String fileName,String dir)  {
  38. this.INSTALL_DIR=dir;
  39. this.IP_FILE=fileName;
  40. ipCache = new HashMap<String, IPLocation>();
  41. loc = new IPLocation();
  42. buf = new byte[100];
  43. b4 = new byte[4];
  44. b3 = new byte[3];
  45. try {
  46. ipFile = new RandomAccessFile(IP_FILE, "r");
  47. } catch (FileNotFoundException e) {
  48. // 如果找不到这个文件,再尝试再当前目录下搜索,这次全部改用小写文件名
  49. //     因为有些系统可能区分大小写导致找不到ip地址信息文件
  50. String filename = new File(IP_FILE).getName().toLowerCase();
  51. File[] files = new File(INSTALL_DIR).listFiles();
  52. for(int i = 0; i < files.length; i++) {
  53. if(files[i].isFile()) {
  54. if(files[i].getName().toLowerCase().equals(filename)) {
  55. try {
  56. ipFile = new RandomAccessFile(files[i], "r");
  57. } catch (FileNotFoundException e1) {
  58. LogFactory.log("IP地址信息文件没有找到,IP显示功能将无法使用",Level.ERROR,e1);
  59. ipFile = null;
  60. }
  61. break;
  62. }
  63. }
  64. }
  65. }
  66. // 如果打开文件成功,读取文件头信息
  67. if(ipFile != null) {
  68. try {
  69. ipBegin = readLong4(0);
  70. ipEnd = readLong4(4);
  71. if(ipBegin == -1 || ipEnd == -1) {
  72. ipFile.close();
  73. ipFile = null;
  74. }
  75. } catch (IOException e) {
  76. LogFactory.log("IP地址信息文件格式有错误,IP显示功能将无法使用",Level.ERROR,e);
  77. ipFile = null;
  78. }
  79. }
  80. }
  81. /**
  82. * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
  83. * @param s 地点子串
  84. * @return 包含IPEntry类型的List
  85. */
  86. public List getIPEntriesDebug(String s) {
  87. List<IPEntry> ret = new ArrayList<IPEntry>();
  88. long endOffset = ipEnd + 4;
  89. for(long offset = ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
  90. // 读取结束IP偏移
  91. long temp = readLong3(offset);
  92. // 如果temp不等于-1,读取IP的地点信息
  93. if(temp != -1) {
  94. IPLocation ipLoc = getIPLocation(temp);
  95. // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
  96. if(ipLoc.getCountry().indexOf(s) != -1 || ipLoc.getArea().indexOf(s) != -1) {
  97. IPEntry entry = new IPEntry();
  98. entry.country = ipLoc.getCountry();
  99. entry.area = ipLoc.getArea();
  100. // 得到起始IP
  101. readIP(offset - 4, b4);
  102. entry.beginIp = Util.getIpStringFromBytes(b4);
  103. // 得到结束IP
  104. readIP(temp, b4);
  105. entry.endIp = Util.getIpStringFromBytes(b4);
  106. // 添加该记录
  107. ret.add(entry);
  108. }
  109. }
  110. }
  111. return ret;
  112. }
  113. public IPLocation getIPLocation(String ip){
  114. IPLocation location=new IPLocation();
  115. location.setArea(this.getArea(ip));
  116. location.setCountry(this.getCountry(ip));
  117. return location;
  118. }
  119. /**
  120. * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
  121. * @param s 地点子串
  122. * @return 包含IPEntry类型的List
  123. */
  124. public List<IPEntry> getIPEntries(String s) {
  125. List<IPEntry> ret = new ArrayList<IPEntry>();
  126. try {
  127. // 映射IP信息文件到内存中
  128. if(mbb == null) {
  129. FileChannel fc = ipFile.getChannel();
  130. mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());
  131. mbb.order(ByteOrder.LITTLE_ENDIAN);
  132. }
  133. int endOffset = (int)ipEnd;
  134. for(int offset = (int)ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
  135. int temp = readInt3(offset);
  136. if(temp != -1) {
  137. IPLocation ipLoc = getIPLocation(temp);
  138. // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
  139. if(ipLoc.getCountry().indexOf(s) != -1 || ipLoc.getArea().indexOf(s) != -1) {
  140. IPEntry entry = new IPEntry();
  141. entry.country = ipLoc.getCountry();
  142. entry.area = ipLoc.getArea();
  143. // 得到起始IP
  144. readIP(offset - 4, b4);
  145. entry.beginIp = Util.getIpStringFromBytes(b4);
  146. // 得到结束IP
  147. readIP(temp, b4);
  148. entry.endIp = Util.getIpStringFromBytes(b4);
  149. // 添加该记录
  150. ret.add(entry);
  151. }
  152. }
  153. }
  154. } catch (IOException e) {
  155. LogFactory.log("",Level.ERROR,e);
  156. }
  157. return ret;
  158. }
  159. /**
  160. * 从内存映射文件的offset位置开始的3个字节读取一个int
  161. * @param offset
  162. * @return
  163. */
  164. private int readInt3(int offset) {
  165. mbb.position(offset);
  166. return mbb.getInt() & 0x00FFFFFF;
  167. }
  168. /**
  169. * 从内存映射文件的当前位置开始的3个字节读取一个int
  170. * @return
  171. */
  172. private int readInt3() {
  173. return mbb.getInt() & 0x00FFFFFF;
  174. }
  175. /**
  176. * 根据IP得到国家名
  177. * @param ip ip的字节数组形式
  178. * @return 国家名字符串
  179. */
  180. public String getCountry(byte[] ip) {
  181. // 检查ip地址文件是否正常
  182. if(ipFile == null)
  183. return Message.bad_ip_file;
  184. // 保存ip,转换ip字节数组为字符串形式
  185. String ipStr = Util.getIpStringFromBytes(ip);
  186. // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
  187. if(ipCache.containsKey(ipStr)) {
  188. IPLocation ipLoc = ipCache.get(ipStr);
  189. return ipLoc.getCountry();
  190. } else {
  191. IPLocation ipLoc = getIPLocation(ip);
  192. ipCache.put(ipStr, ipLoc.getCopy());
  193. return ipLoc.getCountry();
  194. }
  195. }
  196. /**
  197. * 根据IP得到国家名
  198. * @param ip IP的字符串形式
  199. * @return 国家名字符串
  200. */
  201. public String getCountry(String ip) {
  202. return getCountry(Util.getIpByteArrayFromString(ip));
  203. }
  204. /**
  205. * 根据IP得到地区名
  206. * @param ip ip的字节数组形式
  207. * @return 地区名字符串
  208. */
  209. public String getArea(byte[] ip) {
  210. // 检查ip地址文件是否正常
  211. if(ipFile == null)
  212. return Message.bad_ip_file;
  213. // 保存ip,转换ip字节数组为字符串形式
  214. String ipStr = Util.getIpStringFromBytes(ip);
  215. // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
  216. if(ipCache.containsKey(ipStr)) {
  217. IPLocation ipLoc = ipCache.get(ipStr);
  218. return ipLoc.getArea();
  219. } else {
  220. IPLocation ipLoc = getIPLocation(ip);
  221. ipCache.put(ipStr, ipLoc.getCopy());
  222. return ipLoc.getArea();
  223. }
  224. }
  225. /**
  226. * 根据IP得到地区名
  227. * @param ip IP的字符串形式
  228. * @return 地区名字符串
  229. */
  230. public String getArea(String ip) {
  231. return getArea(Util.getIpByteArrayFromString(ip));
  232. }
  233. /**
  234. * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到
  235. * @param ip 要查询的IP
  236. * @return IPLocation结构
  237. */
  238. private IPLocation getIPLocation(byte[] ip) {
  239. IPLocation info = null;
  240. long offset = locateIP(ip);
  241. if(offset != -1)
  242. info = getIPLocation(offset);
  243. if(info == null) {
  244. info = new IPLocation();
  245. info.setCountry (  Message.unknown_country);
  246. info.setArea(Message.unknown_area);
  247. }
  248. return info;
  249. }
  250. /**
  251. * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法
  252. * 用了这么一个函数来做转换
  253. * @param offset
  254. * @return 读取的long值,返回-1表示读取文件失败
  255. */
  256. private long readLong4(long offset) {
  257. long ret = 0;
  258. try {
  259. ipFile.seek(offset);
  260. ret |= (ipFile.readByte() & 0xFF);
  261. ret |= ((ipFile.readByte() << 8) & 0xFF00);
  262. ret |= ((ipFile.readByte() << 16) & 0xFF0000);
  263. ret |= ((ipFile.readByte() << 24) & 0xFF000000);
  264. return ret;
  265. } catch (IOException e) {
  266. return -1;
  267. }
  268. }
  269. /**
  270. * 从offset位置读取3个字节为一个long,因为java为big-endian格式,所以没办法
  271. * 用了这么一个函数来做转换
  272. * @param offset 整数的起始偏移
  273. * @return 读取的long值,返回-1表示读取文件失败
  274. */
  275. private long readLong3(long offset) {
  276. long ret = 0;
  277. try {
  278. ipFile.seek(offset);
  279. ipFile.readFully(b3);
  280. ret |= (b3[0] & 0xFF);
  281. ret |= ((b3[1] << 8) & 0xFF00);
  282. ret |= ((b3[2] << 16) & 0xFF0000);
  283. return ret;
  284. } catch (IOException e) {
  285. return -1;
  286. }
  287. }
  288. /**
  289. * 从当前位置读取3个字节转换成long
  290. * @return 读取的long值,返回-1表示读取文件失败
  291. */
  292. private long readLong3() {
  293. long ret = 0;
  294. try {
  295. ipFile.readFully(b3);
  296. ret |= (b3[0] & 0xFF);
  297. ret |= ((b3[1] << 8) & 0xFF00);
  298. ret |= ((b3[2] << 16) & 0xFF0000);
  299. return ret;
  300. } catch (IOException e) {
  301. return -1;
  302. }
  303. }
  304. /**
  305. * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
  306. * 文件中是little-endian形式,将会进行转换
  307. * @param offset
  308. * @param ip
  309. */
  310. private void readIP(long offset, byte[] ip) {
  311. try {
  312. ipFile.seek(offset);
  313. ipFile.readFully(ip);
  314. byte temp = ip[0];
  315. ip[0] = ip[3];
  316. ip[3] = temp;
  317. temp = ip[1];
  318. ip[1] = ip[2];
  319. ip[2] = temp;
  320. } catch (IOException e) {
  321. LogFactory.log("",Level.ERROR,e);
  322. }
  323. }
  324. /**
  325. * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
  326. * 文件中是little-endian形式,将会进行转换
  327. * @param offset
  328. * @param ip
  329. */
  330. private void readIP(int offset, byte[] ip) {
  331. mbb.position(offset);
  332. mbb.get(ip);
  333. byte temp = ip[0];
  334. ip[0] = ip[3];
  335. ip[3] = temp;
  336. temp = ip[1];
  337. ip[1] = ip[2];
  338. ip[2] = temp;
  339. }
  340. /**
  341. * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的
  342. * @param ip 要查询的IP
  343. * @param beginIp 和被查询IP相比较的IP
  344. * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。
  345. */
  346. private int compareIP(byte[] ip, byte[] beginIp) {
  347. for(int i = 0; i < 4; i++) {
  348. int r = compareByte(ip[i], beginIp[i]);
  349. if(r != 0)
  350. return r;
  351. }
  352. return 0;
  353. }
  354. /**
  355. * 把两个byte当作无符号数进行比较
  356. * @param b1
  357. * @param b2
  358. * @return 若b1大于b2则返回1,相等返回0,小于返回-1
  359. */
  360. private int compareByte(byte b1, byte b2) {
  361. if((b1 & 0xFF) > (b2 & 0xFF)) // 比较是否大于
  362. return 1;
  363. else if((b1 ^ b2) == 0)// 判断是否相等
  364. return 0;
  365. else
  366. return -1;
  367. }
  368. /**
  369. * 这个方法将根据ip的内容,定位到包含这个ip国家地区的记录处,返回一个绝对偏移
  370. * 方法使用二分法查找。
  371. * @param ip 要查询的IP
  372. * @return 如果找到了,返回结束IP的偏移,如果没有找到,返回-1
  373. */
  374. private long locateIP(byte[] ip) {
  375. long m = 0;
  376. int r;
  377. // 比较第一个ip项
  378. readIP(ipBegin, b4);
  379. r = compareIP(ip, b4);
  380. if(r == 0) return ipBegin;
  381. else if(r < 0) return -1;
  382. // 开始二分搜索
  383. for(long i = ipBegin, j = ipEnd; i < j; ) {
  384. m = getMiddleOffset(i, j);
  385. readIP(m, b4);
  386. r = compareIP(ip, b4);
  387. // log.debug(Utils.getIpStringFromBytes(b));
  388. if(r > 0)
  389. i = m;
  390. else if(r < 0) {
  391. if(m == j) {
  392. j -= IP_RECORD_LENGTH;
  393. m = j;
  394. } else
  395. j = m;
  396. } else
  397. return readLong3(m + 4);
  398. }
  399. // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非
  400. //     肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移
  401. m = readLong3(m + 4);
  402. readIP(m, b4);
  403. r = compareIP(ip, b4);
  404. if(r <= 0) return m;
  405. else return -1;
  406. }
  407. /**
  408. * 得到begin偏移和end偏移中间位置记录的偏移
  409. * @param begin
  410. * @param end
  411. * @return
  412. */
  413. private long getMiddleOffset(long begin, long end) {
  414. long records = (end - begin) / IP_RECORD_LENGTH;
  415. records >>= 1;
  416. if(records == 0) records = 1;
  417. return begin + records * IP_RECORD_LENGTH;
  418. }
  419. /**
  420. * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构
  421. * @param offset 国家记录的起始偏移
  422. * @return IPLocation对象
  423. */
  424. private IPLocation getIPLocation(long offset) {
  425. try {
  426. // 跳过4字节ip
  427. ipFile.seek(offset + 4);
  428. // 读取第一个字节判断是否标志字节
  429. byte b = ipFile.readByte();
  430. if(b == REDIRECT_MODE_1) {
  431. // 读取国家偏移
  432. long countryOffset = readLong3();
  433. // 跳转至偏移处
  434. ipFile.seek(countryOffset);
  435. // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
  436. b = ipFile.readByte();
  437. if(b == REDIRECT_MODE_2) {
  438. loc.setCountry (  readString(readLong3()));
  439. ipFile.seek(countryOffset + 4);
  440. } else
  441. loc.setCountry ( readString(countryOffset));
  442. // 读取地区标志
  443. loc.setArea( readArea(ipFile.getFilePointer()));
  444. } else if(b == REDIRECT_MODE_2) {
  445. loc.setCountry ( readString(readLong3()));
  446. loc.setArea( readArea(offset + 8));
  447. } else {
  448. loc.setCountry (  readString(ipFile.getFilePointer() - 1));
  449. loc.setArea( readArea(ipFile.getFilePointer()));
  450. }
  451. return loc;
  452. } catch (IOException e) {
  453. return null;
  454. }
  455. }
  456. /**
  457. * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构,此方法应用与内存映射文件方式
  458. * @param offset 国家记录的起始偏移
  459. * @return IPLocation对象
  460. */
  461. private IPLocation getIPLocation(int offset) {
  462. // 跳过4字节ip
  463. mbb.position(offset + 4);
  464. // 读取第一个字节判断是否标志字节
  465. byte b = mbb.get();
  466. if(b == REDIRECT_MODE_1) {
  467. // 读取国家偏移
  468. int countryOffset = readInt3();
  469. // 跳转至偏移处
  470. mbb.position(countryOffset);
  471. // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
  472. b = mbb.get();
  473. if(b == REDIRECT_MODE_2) {
  474. loc.setCountry (  readString(readInt3()));
  475. mbb.position(countryOffset + 4);
  476. } else
  477. loc.setCountry (  readString(countryOffset));
  478. // 读取地区标志
  479. loc.setArea(readArea(mbb.position()));
  480. } else if(b == REDIRECT_MODE_2) {
  481. loc.setCountry ( readString(readInt3()));
  482. loc.setArea(readArea(offset + 8));
  483. } else {
  484. loc.setCountry (  readString(mbb.position() - 1));
  485. loc.setArea(readArea(mbb.position()));
  486. }
  487. return loc;
  488. }
  489. /**
  490. * 从offset偏移开始解析后面的字节,读出一个地区名
  491. * @param offset 地区记录的起始偏移
  492. * @return 地区名字符串
  493. * @throws IOException
  494. */
  495. private String readArea(long offset) throws IOException {
  496. ipFile.seek(offset);
  497. byte b = ipFile.readByte();
  498. if(b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
  499. long areaOffset = readLong3(offset + 1);
  500. if(areaOffset == 0)
  501. return Message.unknown_area;
  502. else
  503. return readString(areaOffset);
  504. } else
  505. return readString(offset);
  506. }
  507. /**
  508. * @param offset 地区记录的起始偏移
  509. * @return 地区名字符串
  510. */
  511. private String readArea(int offset) {
  512. mbb.position(offset);
  513. byte b = mbb.get();
  514. if(b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
  515. int areaOffset = readInt3();
  516. if(areaOffset == 0)
  517. return Message.unknown_area;
  518. else
  519. return readString(areaOffset);
  520. } else
  521. return readString(offset);
  522. }
  523. /**
  524. * 从offset偏移处读取一个以0结束的字符串
  525. * @param offset 字符串起始偏移
  526. * @return 读取的字符串,出错返回空字符串
  527. */
  528. private String readString(long offset) {
  529. try {
  530. ipFile.seek(offset);
  531. int i;
  532. for(i = 0, buf[i] = ipFile.readByte(); buf[i] != 0; buf[++i] = ipFile.readByte());
  533. if(i != 0)
  534. return Util.getString(buf, 0, i, "GBK");
  535. } catch (IOException e) {
  536. LogFactory.log("",Level.ERROR,e);
  537. }
  538. return "";
  539. }
  540. /**
  541. * 从内存映射文件的offset位置得到一个0结尾字符串
  542. * @param offset 字符串起始偏移
  543. * @return 读取的字符串,出错返回空字符串
  544. */
  545. private String readString(int offset) {
  546. try {
  547. mbb.position(offset);
  548. int i;
  549. for(i = 0, buf[i] = mbb.get(); buf[i] != 0; buf[++i] = mbb.get());
  550. if(i != 0)
  551. return Util.getString(buf, 0, i, "GBK");
  552. } catch (IllegalArgumentException e) {
  553. LogFactory.log("",Level.ERROR,e);
  554. }
  555. return "";
  556. }
  557. }

在实际项目用我使用spring注入IP地址库文件的名字和所在目录,并能保证IPSeeker的单一实例。

下面是个工具类,把string和btye数组之间互相转换的类。

Java代码 
  1. package com.showtime.IPparse;
  2. import java.io.UnsupportedEncodingException;
  3. import java.util.StringTokenizer;
  4. import org.apache.log4j.Level;
  5. import  com.showtime.util.LogFactory;
  6. /**
  7. * 工具类,提供一些方便的方法
  8. */
  9. public class Util {
  10. private static StringBuilder sb = new StringBuilder();
  11. /**
  12. * 从ip的字符串形式得到字节数组形式
  13. * @param ip 字符串形式的ip
  14. * @return 字节数组形式的ip
  15. */
  16. public static byte[] getIpByteArrayFromString(String ip) {
  17. byte[] ret = new byte[4];
  18. StringTokenizer st = new StringTokenizer(ip, ".");
  19. try {
  20. ret[0] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);
  21. ret[1] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);
  22. ret[2] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);
  23. ret[3] = (byte)(Integer.parseInt(st.nextToken()) & 0xFF);
  24. } catch (Exception e) {
  25. LogFactory.log("从ip的字符串形式得到字节数组形式报错", Level.ERROR, e);
  26. }
  27. return ret;
  28. }
  29. /**
  30. * @param ip ip的字节数组形式
  31. * @return 字符串形式的ip
  32. */
  33. public static String getIpStringFromBytes(byte[] ip) {
  34. sb.delete(0, sb.length());
  35. sb.append(ip[0] & 0xFF);
  36. sb.append('.');
  37. sb.append(ip[1] & 0xFF);
  38. sb.append('.');
  39. sb.append(ip[2] & 0xFF);
  40. sb.append('.');
  41. sb.append(ip[3] & 0xFF);
  42. return sb.toString();
  43. }
  44. /**
  45. * 根据某种编码方式将字节数组转换成字符串
  46. * @param b 字节数组
  47. * @param offset 要转换的起始位置
  48. * @param len 要转换的长度
  49. * @param encoding 编码方式
  50. * @return 如果encoding不支持,返回一个缺省编码的字符串
  51. */
  52. public static String getString(byte[] b, int offset, int len, String encoding) {
  53. try {
  54. return new String(b, offset, len, encoding);
  55. } catch (UnsupportedEncodingException e) {
  56. return new String(b, offset, len);
  57. }
  58. }
  59. }

下面是个常量值的类,用接口形式来定义省事不少。

Java代码 
  1. package com.showtime.IPparse;
  2. public interface Message {
  3. String bad_ip_file="IP地址库文件错误";
  4. String unknown_country="未知国家";
  5. String unknown_area="未知地区";
  6. }

一个封装国家和地区的实体类

Java代码 
  1. package com.showtime.IPparse;
  2. /**
  3. *
  4. * @category 用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区
  5. */
  6. public class IPLocation {
  7. private String country;
  8. private String area;
  9. public IPLocation() {
  10. country = area = "";
  11. }
  12. public IPLocation getCopy() {
  13. IPLocation ret = new IPLocation();
  14. ret.country = country;
  15. ret.area = area;
  16. return ret;
  17. }
  18. public String getCountry() {
  19. return country;
  20. }
  21. public void setCountry(String country) {
  22. this.country = country;
  23. }
  24. public String getArea() {
  25. return area;
  26. }
  27. public void setArea(String area) {
  28. //如果为局域网,纯真IP地址库的地区会显示CZ88.NET,这里把它去掉
  29. if(area.trim().equals("CZ88.NET")){
  30. this.area="本机或本网络";
  31. }else{
  32. this.area = area;
  33. }
  34. }
  35. }

一下是一个范围记录的类

Java代码 
  1. package com.showtime.IPparse;
  2. /**
  3. * <pre>
  4. * 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP
  5. * </pre>
  6. */
  7. public class IPEntry {
  8. public String beginIp;
  9. public String endIp;
  10. public String country;
  11. public String area;
  12. /**
  13. * 构造函数
  14. */
  15. public IPEntry() {
  16. beginIp = endIp = country = area = "";
  17. }
  18. }

日志记录类

Java代码 
  1. package com.showtime.util;
  2. import org.apache.log4j.Level;
  3. import org.apache.log4j.Logger;
  4. /**
  5. *
  6. *
  7. * 日志工厂
  8. */
  9. public class LogFactory {
  10. private static final Logger logger;
  11. static {
  12. logger = Logger.getLogger("stdout");
  13. logger.setLevel(Level.DEBUG);
  14. }
  15. public static void log(String info, Level level, Throwable ex) {
  16. logger.log(level, info, ex);
  17. }
  18. public static Level  getLogLevel(){
  19. return logger.getLevel();
  20. }
  21. }

下面是测试类

Java代码 
  1. package com.showtime.IPparse;
  2. import junit.framework.TestCase;
  3. public class IPtest extends TestCase {
  4. public void testIp(){
  5. //指定纯真数据库的文件名,所在文件夹
  6. IPSeeker ip=new IPSeeker("QQWry.Dat","f:/qqwry");
  7. //测试IP 58.20.43.13
  8. System.out.println(ip.getIPLocation("58.20.43.13").getCountry()+":"+ip.getIPLocation("58.20.43.13").getArea());
  9. }
  10. }

当输出:湖南省长沙市:网通

JAVA:实现解析纯真IP数据库相关推荐

  1. c++ 解析纯真IP数据库qqwry

    http://www.cdut-boy.com/2011/09/22/parseqqwry/ 网上流传的IP数据库等,如纯真,其实是cnss制定的格式. 在项目中有需求,网上找到的几份已有的实现,都不 ...

  2. java解析纯真IP数据库

    原文地址: http://www.blogjava.net/libin2722/articles/338316.html 转载于:https://blog.51cto.com/7090376/1592 ...

  3. JAVA解析纯真IP地址库

    2019独角兽企业重金招聘Python工程师标准>>> 用java实现对纯真IP数据库的查询,首先到网上下载QQwry.da文件,读取代码如下: 1.IP记录实体类 package ...

  4. java读取纯真IP数据库qqwry.dat的源代码

    java读取纯真IP数据库QQwry.dat的源代码,要运行此程序必须有 到网上下载QQwry.dat,下载地址 http://www.cz88.net/down/   由于太大,我这里就不提供了. ...

  5. Java 解析纯真IP库

    JAVA解析纯真IP地址库 博客分类: JAVA Java log4j Cache 数据结构 J#  前几天看了下Ruby的IPParse,觉得很过瘾,上网查了下貌似很多IP数据库都要收费的,就下了个 ...

  6. 基于 cz88 纯真IP数据库开发的 IP 解析服务 - 支持 http 协议请求或 rpc 协议请求,也支持第三方包的方式引入直接使用

    cz88 基于 cz88 纯真IP数据库开发的 IP 解析服务 - 支持 http 协议请求或 rpc 协议请求,也支持第三方包的方式引入直接使用 Go 语言编写 进程内缓存结果,重复的 ip 查询响 ...

  7. 纯真IP数据库格式详解

    摘要 网络上的IP数据库以纯真版的最为流行,LumaQQ也采用了纯真版IP数据库做为IP查询功能的基础.不过关于其格式的文档却非常之少,后来终于在网上 找到了一份文档,得以了解其内幕,不过那份文档寥寥 ...

  8. 纯真IP数据库格式详解zt

    摘要 网络上的IP数据库以纯真版的最为流行,LumaQQ也采用了纯真版IP数据库做为IP查询功能的基础.不过关于其格式的文档却非常之少,后来终于在网上找到了一份文档,得以了解其内幕,不过那份文档寥寥数 ...

  9. ip解析 java_JAVA解析纯真IP地址库

    http://lumaqq.linuxsir.org/article/qqwry_format_detail.html,这里就不多叙述了. 看下JAVA代码中怎么解析IP的吧.(代码参考至lumaQQ ...

  10. [转]纯真IP数据库格式详解

    纯真IP数据库格式详解 摘要 网络上的IP数据库以纯真版的最为流行,LumaQQ也采用了纯真版IP数据库做为IP查询功能的基础.不过关于其格式的文档却非常之少,后来终于在网上找到了一份文档,得以了解其 ...

最新文章

  1. Uva(10048),最短路Floyd
  2. 使用Ant Design 和Vue,React中后台开发套餐
  3. Dubbo(六)之属性配置
  4. 原生DOM选择器querySelector和querySelectorAll
  5. Docker架构、常用命令和示例
  6. 博弈论 ----- Nim游戏
  7. 2018-12-26 课堂笔记 for循环
  8. Python自动化开发从浅入深-进阶(socketServer)
  9. 多线程_18_并发_同步_快乐影院_快乐火车票
  10. 中兴流媒体服务器,中兴通讯增强型MEC边缘服务器,满足5G业务极致体验需求
  11. 微信小程序————样式
  12. Netron简单使用教程
  13. LabVIEW编程LabVIEW控制PXI-5122例程与相关资料
  14. 2021-2025年中国阿莫雷德行业市场供需与战略研究报告
  15. costas环 matlab,数字Costas环的matlab仿真及其FPGA实现
  16. golang快速入门[6.2]-集成开发环境-emacs详解
  17. 异常:Activity has leaked window com.android.internal.policy.impl.PhoneWindow
  18. caused by: java.lang.outofmemory_hadoop运行java.lang.OutOfMemoryError:java heap space错误。
  19. 新套路+老配方 | 2023年网络钓鱼攻击新方式
  20. 车载毫米波雷达的性能标准与测试方法

热门文章

  1. 笔记:C# log4net App.config 配置系统未能初始化问题的一种处理方法
  2. 计算机考试报名照片可以是白底吗,软考报名照片必须白底的是吗?
  3. vivado 2018 下载地址
  4. 【领域建模】UML类图工具推荐
  5. PLINK-GWAS学习9------对于二元数据的关联分析
  6. U8系统管理员怎么登录服务器,u8客户端如何登录服务器
  7. 三运放差分放大电路分析_运放19——三运放仪表放大器工作原理分析
  8. Mybatis学习文档
  9. 视频格式转换库--libyuv的简介与编译
  10. 【CAN】CAN的比特率和波特率