现在的位置: 首页 > 移动开发> 正文
电话归属地查询之Android解决方案
2011年08月14日 移动开发 评论数 1 ⁄ 被围观 6,725+

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

本文的基本思路如下:

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

1898742 1898743 1898744 :云南曲靖

1894380 1894381 1894382 :吉林松原

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

1894815 --> 1899819 :广东珠海,

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

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

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

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

4. 归属地查询

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

程序设计,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
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<Long, String> generateTestData() {
          HashMap<Long, String>
          telToAreaCode = new HashMap<Long, String>();
          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<String> strs = readFileToList(souceFile);
         HashMap<Long, String>
         telToArea = createTel2AreaHashMap(strs);
         writeDate(indexFilePath + INDEXDATAFILE, telToArea);
   }
 
   /**   * read file content to String array list, every line one string.    * */
   private ArrayList<String> readFileToList(String filePath) {
        final ArrayList<String>
        strLists = new ArrayList<String>();
 
        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<Long, String> createTel2AreaHashMap(ArrayList<String> strs) {
           final HashMap<Long, String>
           telToArea = new HashMap<Long, String>();
 
           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<Record> 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<Long, String> telToAreaCode) {
       // 1. get all area info
       ArrayList<String> tmpAreaCodes = new ArrayList<String>(telToAreaCode.values());
       ArrayList<String> strAreaCodes = new ArrayList<String>();
       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<Long> telNunms = new ArrayList<Long>(telToAreaCode.keySet());
       Collections.sort(telNunms);
       ArrayList<Record> records = new ArrayList<Record>();
       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;
     }
  }
}
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<Long, String> generateTestData() {
          HashMap<Long, String>
          telToAreaCode = new HashMap<Long, String>();
          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<String> strs = readFileToList(souceFile);
         HashMap<Long, String>
         telToArea = createTel2AreaHashMap(strs);
         writeDate(indexFilePath + INDEXDATAFILE, telToArea);
   }

   /**	 * read file content to String array list, every line one string.	 * */
   private ArrayList<String> readFileToList(String filePath) {
        final ArrayList<String>
        strLists = new ArrayList<String>();

        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<Long, String> createTel2AreaHashMap(ArrayList<String> strs) {
           final HashMap<Long, String>
           telToArea = new HashMap<Long, String>();

           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<Record> 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<Long, String> telToAreaCode) {
       // 1. get all area info
       ArrayList<String> tmpAreaCodes = new ArrayList<String>(telToAreaCode.values());
       ArrayList<String> strAreaCodes = new ArrayList<String>();
       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<Long> telNunms = new ArrayList<Long>(telToAreaCode.keySet());
       Collections.sort(telNunms);
       ArrayList<Record> records = new ArrayList<Record>();
       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 : 湖北武汉
2ms
1301815 : 四川泸州
2ms
没有预测1301816 : null
2ms
根据号码连贯性原理预测1301816 : 四川泸州
1ms
1301817 : 四川宜宾
2ms

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

本程序的测试data文件下载telinfo

【上篇】
【下篇】

目前有 1 条留言 其中:访客:0 条, 博主:1 条

  1. 润物无声 : 2012年03月01日19:43:01  -49楼 @回复 回复

    未经处理的Txt格式的手机号码归属地文件和经过压缩处理的二进制格式的手机归属地文件,请在这里下载(手机归属地信息

给我留言

留言无头像?


×
腾讯微博