1. java读取纯真IP数据库QQwry.dat的源代码,要运行此程序必须到网上下载QQwry.da,由于太大,我这里就不提供了。
2. 一、IPEntry.java
3. /** *
4. * 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP *
5.
6. *
7. * @author
8. */
9. public class
10. public
11. public
12. public
13. public
14.
15. /**
16. * 构造函数
17. */
18.
19.
20. public
21. ""
22. }
23.
24. public
25. this .area+ " " + this .country+ "IP范围:" + this .beginIp+ "-" + this
26. }
27. }
28.
29. 二、Utils.java
30.
31. /*
32. * Created on 2004-8-4
33. *
34. */
35. import
36. /**
37. * @author LJ-silver
38. */
39. public class
40. /**
41. * 从ip的字符串形式得到字节数组形式
42. * @param ip 字符串形式的ip
43. * @return 字节数组形式的ip
44. */
45. public static byte
46. byte [] ret = new byte [ 4
47. new java.util.StringTokenizer(ip, "."
48. try
49. 0 ] = ( byte )(Integer.parseInt(st.nextToken()) & 0xFF
50. 1 ] = ( byte )(Integer.parseInt(st.nextToken()) & 0xFF
51. 2 ] = ( byte )(Integer.parseInt(st.nextToken()) & 0xFF
52. 3 ] = ( byte )(Integer.parseInt(st.nextToken()) & 0xFF
53. catch
54. System.out.println(e.getMessage());
55. }
56. return
57. }
58.
59. public static void
60. byte [] a=getIpByteArrayFromString(args[ 0
61. for ( int i= 0
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
73. try
74. return new
75. catch
76. return
77. }
78. }
79.
80. /**
81. * 根据某种编码方式将字节数组转换成字符串
82. * @param b 字节数组
83. * @param encoding 编码方式
84. * @return 如果encoding不支持,返回一个缺省编码的字符串
85. */
86. public static String getString( byte
87. try
88. return new
89. catch
90. return new
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
103. try
104. return new
105. catch
106. return new
107. }
108. }
109.
110. /**
111. * @param ip ip的字节数组形式
112. * @return 字符串形式的ip
113. */
114. public static String getIpStringFromBytes( byte
115. new
116. 0 ] & 0xFF
117. '.'
118. 1 ] & 0xFF
119. '.'
120. 2 ] & 0xFF
121. '.'
122. 3 ] & 0xFF
123. return
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
149. import
150. import
151. import
152. import
153. import
154. import
155. import
156. import
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
190. /**
191. *
192.
193. * 用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区
194. *
195.
196.
197. *
198. * @author 马若劼
199. */
200. private class
201. public
202. public
203. public
204. ""
205. }
206. public
207. new
208. ret.country = country;
209. ret.area = area;
210. return
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
220. // 随机文件访问类
221. private
222. // 内存映射文件
223. private
224. // 单一模式实例
225. private static IPSeeker instance = new
226. // 起始地区的开始和结束的绝对偏移
227. private long
228. // 为提高效率而采用的临时变量
229. private
230. private byte
231. private byte
232. private byte
233. /**
234. * 私有构造函数
235. */
236. private
237. new
238. new
239. new byte [ 100
240. new byte [ 4
241. new byte [ 3
242. try
243. new RandomAccessFile(IP_FILE, "r"
244. catch
245. class .getResource( "/QQWry.dat"
246. System.out.println(IP_FILE);
247. "IP地址信息文件没有找到,IP显示功能将无法使用"
248. null
249. }
250. // 如果打开文件成功,读取文件头信息
251. if (ipFile != null
252. try
253. 0
254. 4
255. if (ipBegin == - 1 || ipEnd == - 1
256. ipFile.close();
257. null
258. }
259. catch
260. "IP地址信息文件格式有错误,IP显示功能将无法使用"
261. null
262. }
263. }
264. }
265. /**
266. * @return 单一实例
267. */
268. public static
269. return
270. }
271. /**
272. * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
273. * @param s 地点子串
274. * @return 包含IPEntry类型的List
275. */
276. public
277. new
278. long endOffset = ipEnd + 4
279. for ( long offset = ipBegin + 4
280. // 读取结束IP偏移
281. long
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. new
288. entry.country = loc.country;
289. entry.area = loc.area;
290. // 得到起始IP
291. 4
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
302. }
303. /**
304. * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
305. * @param s 地点子串
306. * @return 包含IPEntry类型的List
307. */
308. public
309. new
310. try
311. // 映射IP信息文件到内存中
312. if (mbb == null
313. FileChannel fc = ipFile.getChannel();
314. 0
315. mbb.order(ByteOrder.LITTLE_ENDIAN);
316. }
317. int endOffset = ( int
318. for ( int offset = ( int )ipBegin + 4
319. int
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. new
325. entry.country = loc.country;
326. entry.area = loc.area;
327. // 得到起始IP
328. 4
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
339. System.out.println(e.getMessage());
340. }
341. return
342. }
343. /**
344. * 从内存映射文件的offset位置开始的3个字节读取一个int
345. * @param offset
346. * @return
347. */
348. private int readInt3( int
349. mbb.position(offset);
350. return mbb.getInt() & 0x00FFFFFF
351. }
352. /**
353. * 从内存映射文件的当前位置开始的3个字节读取一个int
354. * @return
355. */
356. private int
357. return mbb.getInt() & 0x00FFFFFF
358. }
359. /**
360. * 根据IP得到国家名
361. * @param ip ip的字节数组形式
362. * @return 国家名字符串
363. */
364. public String getCountry( byte
365. // 检查ip地址文件是否正常
366. if (ipFile == null ) return "错误的IP数据库文件"
367. // 保存ip,转换ip字节数组为字符串形式
368. String ipStr = Utils.getIpStringFromBytes(ip);
369. // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
370. if
371. IPLocation loc = (IPLocation)ipCache.get(ipStr);
372. return
373. else
374. IPLocation loc = getIPLocation(ip);
375. ipCache.put(ipStr, loc.getCopy());
376. return
377. }
378. }
379. /**
380. * 根据IP得到国家名
381. * @param ip IP的字符串形式
382. * @return 国家名字符串
383. */
384. public
385. return
386. }
387. /**
388. * 根据IP得到地区名
389. * @param ip ip的字节数组形式
390. * @return 地区名字符串
391. */
392. public String getArea( byte
393. // 检查ip地址文件是否正常
394. if (ipFile == null ) return "错误的IP数据库文件"
395. // 保存ip,转换ip字节数组为字符串形式
396. String ipStr = Utils.getIpStringFromBytes(ip);
397. // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
398. if
399. IPLocation loc = (IPLocation)ipCache.get(ipStr);
400. return
401. else
402. IPLocation loc = getIPLocation(ip);
403. ipCache.put(ipStr, loc.getCopy());
404. return
405. }
406. }
407. /**
408. * 根据IP得到地区名
409. * @param ip IP的字符串形式
410. * @return 地区名字符串
411. */
412. public
413. return
414. }
415. /**
416. * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到
417. * @param ip 要查询的IP
418. * @return IPLocation结构
419. */
420. private IPLocation getIPLocation( byte
421. null
422. long
423. if (offset != - 1
424. info = getIPLocation(offset);
425. if (info == null
426. new
427. "未知国家"
428. "未知地区"
429. }
430. return
431. }
432. /**
433. * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法
434. * 用了这么一个函数来做转换
435. * @param offset
436. * @return 读取的long值,返回-1表示读取文件失败
437. */
438. private long readLong4( long
439. long ret = 0
440. try
441. ipFile.seek(offset);
442. 0xFF
443. 8 ) & 0xFF00
444. 16 ) & 0xFF0000
445. 24 ) & 0xFF000000
446. return
447. catch
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
458. long ret = 0
459. try
460. ipFile.seek(offset);
461. ipFile.readFully(b3);
462. 0 ] & 0xFF
463. 1 ] << 8 ) & 0xFF00
464. 2 ] << 16 ) & 0xFF0000
465. return
466. catch
467. return - 1
468. }
469. }
470. /**
471. * 从当前位置读取3个字节转换成long
472. * @return
473. */
474. private long
475. long ret = 0
476. try
477. ipFile.readFully(b3);
478. 0 ] & 0xFF
479. 1 ] << 8 ) & 0xFF00
480. 2 ] << 16 ) & 0xFF0000
481. return
482. catch
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
493. try
494. ipFile.seek(offset);
495. ipFile.readFully(ip);
496. byte temp = ip[ 0
497. 0 ] = ip[ 3
498. 3
499. 1
500. 1 ] = ip[ 2
501. 2
502. catch
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
513. mbb.position(offset);
514. mbb.get(ip);
515. byte temp = ip[ 0
516. 0 ] = ip[ 3
517. 3
518. 1
519. 1 ] = ip[ 2
520. 2
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
529. for ( int i = 0 ; i < 4
530. int
531. if (r != 0
532. return
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
543. if ((b1 & 0xFF ) > (b2 & 0xFF )) // 比较是否大于
544. return 1
545. else if ((b1 ^ b2) == 0 ) // 判断是否相等
546. return 0
547. else
548. return
java datahub读取数据 设置编码 java 读取dat文件
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
JAVA 读dat文件 java怎么读取dat文件
java 解析dat_java批量解析微信dat文件
java 解析dat java System 微信 -
java 表示 url分隔符
String类 1、String对象的初始化由于String对象特别常用,所以在对String对象进行初始化时,Java提供了一种简化的特殊语法,格式如下: &n
java 表示 url分隔符 Java 字符串 bc 子串