博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
电话归属地查询之Android解决方案
阅读量:4208 次
发布时间:2019-05-26

本文共 12766 字,大约阅读时间需要 42 分钟。

最近接触的一个项目中,其中有一个功能需求就是号码归属地的查询,乍一看确实挺简单,反正数据库也都有了,只不过就是查询一下而已嘛!到了实际程序设计的时候才发现,5M的数据库光要加载起来就得1分多钟,放在android手机上跑的太慢了,没办法,只好另辟蹊径了!!!

本文的基本思路如下:

1.  先把数据进行分组,即每一个地区一个组,例如

1898742 1898743 1898744 :云南曲靖

1894380 1894381 1894382 :吉林松原

2.  把电话号码进行排序,目的就是为了找到电话号码的区间,例如

1894815 --> 1899819 :广东珠海,

找到了一个区段,这样就不用把每个电话号码读存储下来, 只要存储一个区间就好,

这样可以大大节省存储空间

3. 设计新的存储格式,本文的程序采用如下方式存储

第一条电话记录在文件中的位置偏移 最后一条电话记录在文件中的位置偏移
电话归属地的字符串(例如:辽宁大连,湖北武汉,广东珠海,广东深圳..., 字符串之间以逗号分隔)
第一条电话记录 (例如:1894815{代表号码段起始值} 5{代表连续的号码个数} 2{代表该归属地字符串在所有归属地字符串中的偏移量})
第二条电话记录
...
最后一条电话记录

4. 归属地查询

根据用户输入的电话号码,利用二分查找法可快速定位到该记录在文件中的位置偏移,读出该记录中位置字符串的偏移值,进而查表即可找到归属地

程序设计,源码如下:

package com.carey.tel;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.RandomAccessFile;import java.util.ArrayList;import java.util.Collections;import java.util.Date;import java.util.HashMap;public class JavaTelArea {     private static JavaTelArea jta = null;     private static final String INDEXDATAFILE = "tel.bin";     private static Hearder cacheHearder = null;     private static AreaCode cacheAreaCode = null;     private static String cacheIndexFilePath = null;     public static void main(String[] args) {          JavaTelArea ctc = JavaTelArea.getInstance();          //ctc.genIndexFile("e:\", "e:\telphone.txt");          String indexPath = "e:\";          long startTime = new Date().getTime();          String searchNum = "13889650920";          String res = ctc.searchTel(indexPath, searchNum);          System.out.println(searchNum + " : " + res);          System.out.println(System.currentTimeMillis() - startTime + "ms");          startTime = new Date().getTime();          searchNum = "+8613659867583";          res = ctc.searchTel(indexPath, searchNum);          System.out.println(searchNum + " : " + res);          System.out.println(System.currentTimeMillis() - startTime + "ms");          startTime = new Date().getTime();          searchNum = "1301815";          res = ctc.searchTel(indexPath, searchNum);          System.out.println(searchNum + " : " + res);          System.out.println(System.currentTimeMillis() - startTime + "ms");          startTime = new Date().getTime();          searchNum = "1301816";          res = ctc.searchTel(indexPath, searchNum);          System.out.println("没有预测");          System.out.println(searchNum + " : " + res);          System.out.println(System.currentTimeMillis() - startTime + "ms");          startTime = new Date().getTime();          searchNum = "1301816";	  res = ctc.searchTel(indexPath, searchNum, true);	  System.out.println("根据号码连贯性原理预测");          System.out.println(searchNum + " : " + res);          System.out.println(System.currentTimeMillis() - startTime + "ms");          startTime = new Date().getTime();          searchNum = "1301817";          res = ctc.searchTel(indexPath, searchNum);          System.out.println(searchNum + " : " + res);          System.out.println(System.currentTimeMillis() - startTime + "ms");    }    private HashMap
generateTestData() { HashMap
telToAreaCode = new HashMap
(); telToAreaCode.put(1310944l, "新疆伊犁州"); telToAreaCode.put(1301263l, "新疆伊犁州"); telToAreaCode.put(1301264l, "新疆伊犁州"); telToAreaCode.put(1301260l, "新疆伊犁州"); telToAreaCode.put(955L, "海南"); telToAreaCode.put(1320955l, "海南"); telToAreaCode.put(1320957l, "海南"); telToAreaCode.put(1300561L, "陕西商州"); telToAreaCode.put(1300562L, "陕西商州"); return telToAreaCode; } public static synchronized JavaTelArea getInstance() { if (jta == null) { jta = new JavaTelArea(); } return jta; } /** * Generate Index File (tel.bin) * */ private void genIndexFile(String indexFilePath, String souceFile) { ArrayList
strs = readFileToList(souceFile); HashMap
telToArea = createTel2AreaHashMap(strs); writeDate(indexFilePath + INDEXDATAFILE, telToArea); } /** * read file content to String array list, every line one string. * */ private ArrayList
readFileToList(String filePath) { final ArrayList
strLists = new ArrayList
(); BufferedReader bReader = null; try { bReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath))); String str = bReader.readLine(); while (str != null) { strLists.add(str); str = bReader.readLine(); } } catch (Exception e) { e.printStackTrace(); } finally { if (bReader != null) { try { bReader.close(); } catch (IOException e) { e.printStackTrace(); } } } return strLists; } /** * create telephone number to area hash map. * */ HashMap
createTel2AreaHashMap(ArrayList
strs) { final HashMap
telToArea = new HashMap
(); String[] tels = null; int len = 0; String strArea = null; for (String string : strs) { tels = string.split(" "); len = tels.length; strArea = tels[len - 1].substring(1); for (int i = 0; i < len - 1; i++) { telToArea.put(Long.valueOf(tels[i]), strArea); } } return telToArea; } /** * combined the adjacent Records. * */ private void combinedRecords(ArrayList
records, Record newRecord) { int size = records.size(); if (size > 0&& records.get(size - 1).areacodeIndex == newRecord.areacodeIndex) { // combined Record lastRecord = records.get(size - 1); lastRecord.numCnt = (int) (newRecord.baseTelNum - lastRecord.baseTelNum) + newRecord.numCnt; } else { records.add(newRecord); } } /** * write index info to file. * */ private void writeDate(String filePath, HashMap
telToAreaCode) { // 1. get all area info ArrayList
tmpAreaCodes = new ArrayList
(telToAreaCode.values()); ArrayList
strAreaCodes = new ArrayList
(); for (String str : tmpAreaCodes) { if (!strAreaCodes.contains(str)) { strAreaCodes.add(str); } } tmpAreaCodes.clear(); tmpAreaCodes = null; StringBuffer sb = new StringBuffer(); for (String str : strAreaCodes) { sb.append(str + ","); } sb.deleteCharAt(sb.length() - 1); AreaCode areaCode = new AreaCode(sb.toString()); areaCode.print(); // 2. Sort HashMap and combined the adjacent telephone number ArrayList
telNunms = new ArrayList
(telToAreaCode.keySet()); Collections.sort(telNunms); ArrayList
records = new ArrayList
(); long baseNum = 0; String baseArea = null; int numCnt = 0; for (Long tm : telNunms) { if (numCnt == 0) { baseNum = tm; baseArea = telToAreaCode.get(tm); numCnt = 1; } else { if (tm == baseNum + numCnt && baseArea.equals(telToAreaCode.get(tm))) { numCnt++; } else { combinedRecords(records, new Record(baseNum, numCnt, strAreaCodes.indexOf(baseArea))); baseNum = tm; baseArea = telToAreaCode.get(tm); numCnt = 1; } } } combinedRecords(records, new Record(baseNum, numCnt, strAreaCodes.indexOf(baseArea))); // for (Record record : records) { // record.print(); // } // 3. Write data to the file RandomAccessFile raf = null; try { raf = new RandomAccessFile(filePath, "rw"); raf.seek(0); Hearder hearder = new Hearder(); hearder.firstRecordOffset = hearder.Size() + areaCode.Size(); hearder.lastRecordOffset = hearder.firstRecordOffset + (records.size() - 1) * records.get(0).Size(); hearder.print(); hearder.write(raf); areaCode.write(raf); for (Record record : records) { record.write(raf); } } catch (Exception e) { e.printStackTrace(); } finally { if (raf != null) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } } class Hearder { int firstRecordOffset; int lastRecordOffset; public int Size() { return (Integer.SIZE + Integer.SIZE) / Byte.SIZE; } public void write(RandomAccessFile raf) throws IOException { raf.writeInt(this.firstRecordOffset); raf.writeInt(this.lastRecordOffset); } public void read(RandomAccessFile raf) throws IOException { this.firstRecordOffset = raf.readInt(); this.lastRecordOffset = raf.readInt(); } public void print() { System.out.println("===== Hearder ===== "); System.out.println("[" + firstRecordOffset + " , " + lastRecordOffset + "]"); } } class AreaCode { private String areacode; private String[] codes; public AreaCode() { this(""); } public AreaCode(String areacode) { this.areacode = areacode; this.codes = null; } public int Size() { return areacode.getBytes().length + (Integer.SIZE / Byte.SIZE); } public void print() { System.out.println("===== AreaCode ===== "); System.out.println("[" + areacode.getBytes().length + "]" + areacode); } public void write(RandomAccessFile raf) throws IOException { raf.writeInt(areacode.getBytes().length); raf.write(this.areacode.getBytes()); } public void read(RandomAccessFile raf) throws IOException { byte[] bytes = new byte[raf.readInt()]; raf.read(bytes); this.areacode = new String(bytes); } public String getCodeByIndex(int index) { if (this.codes == null) { this.codes = this.areacode.split(","); } return (index < 0 || this.codes == null || index >= this.codes.length) ? null : this.codes[index]; }}class Record { long baseTelNum; int numCnt; int areacodeIndex; public Record() { this(0, 0, 0); } public Record(long baseTelNum, int numCnt, int areacodeIndex) { this.baseTelNum = baseTelNum; this.numCnt = numCnt; this.areacodeIndex = areacodeIndex; } public void print() { System.out.println("===== Record ===== "); System.out.println("<" + baseTelNum + "> <" + numCnt + "> <" + areacodeIndex + ">"); } public int Size() { return (Long.SIZE + Integer.SIZE) / Byte.SIZE; } public void write(RandomAccessFile raf) throws IOException { raf.writeLong(this.baseTelNum); int tmp = this.numCnt << 16; tmp += 0xFFFF & this.areacodeIndex; raf.writeInt(tmp); } public void read(RandomAccessFile raf) throws IOException { this.baseTelNum = raf.readLong(); int tmp = raf.readInt(); this.numCnt = tmp >> 16; this.areacodeIndex = 0xFFFF & tmp; } public int inWhich(long telNum) { if (telNum < this.baseTelNum) { return -1; } else if (telNum >= this.baseTelNum + this.numCnt) { return 1; } else { return 0; } } } public String searchTel(String indexFilePath, String telNum) { return searchTel(indexFilePath, telNum, false); } /** * search * */ public String searchTel(String indexFilePath, String telNum, boolean forecast) { StringBuffer sb = new StringBuffer(telNum); // + if (sb.charAt(0) == '+') { sb.deleteCharAt(0); } // 86 if (sb.charAt(0) == '8' && sb.charAt(1) == '6') { sb.delete(0, 2); } // 以0开头,是区号 if (sb.charAt(0) == '0') { sb.deleteCharAt(0); // 首先按照4位区号查询,若查询为空,再按3位区号查询 if (sb.length() >= 3) { sb.delete(3, sb.length()); } String dial = searchTel(indexFilePath, Long.valueOf(sb.toString()),false); if (dial != null) { return dial; } if (sb.length() >= 2) { sb.delete(2, sb.length()); } } // 以1开头,是手机号或者服务行业号码 else if (sb.charAt(0) == '1') { // 首先按照手机号码查询,若查询为空,再按特殊号码查询 if (sb.length() > 7) { String dial = searchTel(indexFilePath, Long.valueOf(sb.substring(0, 8)),false); if (dial != null) { return dial; } dial = searchTel(indexFilePath, Long.valueOf(sb.toString()),false); if (dial != null) { return dial; } // 只需要保留7位号码就ok了,多余的删掉 if (sb.length() > 7) { sb.delete(7, sb.length()); } } else { //小于7位,最有可能是服务号码 //do nothing. } } // 以其他数字开头,这也不知道是啥号码了 else { //do nothing. } return searchTel(indexFilePath, Long.valueOf(sb.toString()), forecast); } private String searchTel(String indexFilePath, long telNum, boolean forecast) { RandomAccessFile raf = null; try { raf = new RandomAccessFile(indexFilePath + INDEXDATAFILE, "r"); if (cacheIndexFilePath == null || !cacheIndexFilePath.equals(indexFilePath)) { cacheIndexFilePath = indexFilePath; cacheHearder = new Hearder(); cacheHearder.read(raf); cacheHearder.print(); cacheAreaCode = new AreaCode(); cacheAreaCode.read(raf); cacheAreaCode.print(); } int index = lookUP(raf, cacheHearder.firstRecordOffset, cacheHearder.lastRecordOffset, telNum, forecast); return cacheAreaCode.getCodeByIndex(index); } catch (Exception e) { e.printStackTrace(); } finally { if (raf != null) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } private int lookUP(RandomAccessFile raf, long startpos, long endpos, long looknum, boolean forecast) throws IOException { Record record = new Record(); long seekpos = 0; do { seekpos = startpos + (endpos - startpos) / record.Size() / 2 * record.Size(); raf.seek(seekpos); record.read(raf); if (record.inWhich(looknum) > 0) { startpos = seekpos + record.Size(); } else if (record.inWhich(looknum) < 0) { endpos = seekpos - record.Size(); } else { return record.areacodeIndex; } } while (startpos <= endpos); if (forecast) { return record.areacodeIndex; } else { return -1; } }}

程序运行情况如下:

==== Hearder =====[4554 , 605622]===== AreaCode ===== [4542]北福建南平,福建三明,海果洛,青海海南,...13889650920 : 辽宁大连20ms+8613659867583 : 湖北武汉2ms1301815 : 四川泸州2ms没有预测1301816 : null2ms根据号码连贯性原理预测1301816 : 四川泸州1ms1301817 : 四川宜宾2ms

可以看到,除了第一次查询的时候要加载索引文件大约耗时20ms,以后的查询基本都在1ms,速度非常快了!!!

本程序的测试data文件下载

转载地址:http://nolli.baihongyu.com/

你可能感兴趣的文章
win7下直接安装win10
查看>>
本地硬盘安装win7/XP系统详细[图解教程]
查看>>
俄罗斯----中国人对它的颠覆性---不正确的神话
查看>>
中国大牛市是一场世界大戏 (转载)
查看>>
中国股市是否出现非理性繁荣?(转载)
查看>>
电脑开关那几个小插头怎么插
查看>>
解决Win7 64位玩游戏不兼容的问题
查看>>
inter处理器台电平板p90h3u6怎么完美root
查看>>
中国企业一扎堆 这个产业就完蛋!
查看>>
董宝珍:从股市总市值占GDP比例看本轮牛市的归宿
查看>>
神经性皮炎如何治疗
查看>>
君乐宝换奶粉方法
查看>>
如何办理提前还贷
查看>>
12种逼死“强迫症”的创意家居设计
查看>>
常用药列表
查看>>
宝宝生病
查看>>
各种皮肤病——谁用谁灵!
查看>>
上海房屋租赁合同登记备案证明办理流程
查看>>
持居住证能落户?子女还能在沪高考
查看>>
虚拟机(Vmware)怎么进入BIOS
查看>>