吾将上下而求索……

博客园 首页 新随笔 联系 订阅 管理
  1 import java.io.*;
  2 import java.util.*;
  3 import java.util.regex.Matcher;
  4 import java.util.regex.Pattern;
  5 import java.net.InetAddress;
  6 import java.net.UnknownHostException;
  7 import java.nio.ByteOrder;
  8 import java.nio.MappedByteBuffer;
  9 import java.nio.channels.FileChannel;
 10 
 11 /**
 12 * 纯真ip查询主程序
 13 * QQWry.Dat保存在当前目录
 14 * @author _hhh_
 15 * @version 0.1, 04/23/08
 16 */
 17 public class IpAddress {
 18 
 19    //数据库地址
 20    private String dataPath = "QQWry.dat";
 21    //随机文件访问类
 22    private RandomAccessFile ipFile = null;
 23    //单一模式实例
 24    private static IpAddress instance = new IpAddress();
 25    //ip开始结束位置
 26    private long ipBegin=0L;
 27    private long ipEnd=0L;
 28    //ip总数
 29    private long ipSum=0L;
 30    //国家,地区
 31    private String country="";
 32    private String area="";
 33 
 34    // 一些固定常量,比如记录长度等等
 35    private static final int RECORD_LENGTH = 7;
 36    private static final byte AREA_FOLLOWED = 0x01;
 37    private static final byte NO_AREA = 0x02;
 38 
 39    /*
 40    * 私有构造函数
 41    */
 42    private IpAddress() {
 43        try {
 44            ipFile = new RandomAccessFile(new File(dataPath).getAbsolutePath(), "r");
 45            } catch (FileNotFoundException e) {  
 46            System.out.println("IP地址信息文件没有找到,IP显示功能将无法使用");
 47            e.printStackTrace();
 48        }
 49        if(ipFile != null) {
 50            try {               
 51                ipBegin = byteArrayToLong(readBytes(0,4));
 52                ipEnd = byteArrayToLong(readBytes(4,4));
 53                if(ipBegin == -1 || ipEnd == -1) {
 54                    ipFile.close();
 55                    ipFile = null;
 56                }
 57            } catch (IOException e) {
 58                System.out.println("IP地址信息文件格式有错误,IP显示功能将无法使用");
 59                e.printStackTrace();
 60            }
 61        }
 62        ipSum = (ipEnd-ipBegin)/RECORD_LENGTH+1;
 63    }
 64 
 65    /**
 66    * 在指定位置读取一定数目的字节
 67    * @param offset 位置
 68    * @param num 多少个字节
 69    * @return ret 
 70    */
 71    private byte[] readBytes(long offset, int num) {
 72        byte[] ret = new byte[num];
 73        try {
 74            ipFile.seek(offset);
 75 
 76            for(int i=0; i != num; i++) {
 77                ret[i] = ipFile.readByte();
 78            }
 79            return ret;
 80        } catch (IOException e) {
 81            e.printStackTrace();
 82            System.out.println("读取文件失败_readBytes");
 83            return ret;
 84        }
 85    }
 86 
 87    /**
 88    * 当前位置读取一定数目的字节
 89    * @param num 多少个字节
 90    * @return ret 
 91    */
 92    private byte[] readBytes(int num) {
 93        byte[] ret = new byte[num];
 94        try {
 95            for(int i=0; i != num; i++) {
 96                ret[i] = ipFile.readByte();
 97            }
 98            return ret;
 99        } catch (IOException e) {
100            System.out.println("读取文件失败_readBytes");
101            return ret;
102        }
103    }
104 
105    /**
106    * 对little-endian字节序进行了转换
107    * byte[]转换为long
108    * @param b
109    * @return ret
110    */
111    private long byteArrayToLong(byte[] b) {
112        long ret = 0;
113        for(int i=0; i<b.length; i++) {
114            ret |= ( b[i] << (0x8*i) & (0xFF * (long)(Math.pow(0x100,i))) );
115        }
116        return ret;
117    }
118 
119    /**
120    * 对little-endian字节序进行了转换
121    * @param ip ip的字节数组形式
122    * @return ip的字符串形式
123    */
124    private String byteArrayToStringIp(byte[] ip) {
125        StringBuffer sb = new StringBuffer();
126        for(int i=ip.length-1; i>=0; i--) {
127            sb.append(ip[i] & 0xFF);
128            sb.append(".");
129        }
130        sb.deleteCharAt(sb.length()-1);
131        return sb.toString();
132    }
133 
134    /**
135    * 把ip字符串转换为long型
136    * @param ip
137    * @return long
138    */
139    private long StingIpToLong(String ip) {
140        String[] arr = ip.split("\\.");
141        return (Long.valueOf(arr[0])*0x1000000 +
142                Long.valueOf(arr[1])*0x10000 +
143                Long.valueOf(arr[2])*0x100 +
144                Long.valueOf(arr[3]));   
145    }
146 
147    /**
148    * 搜索ip,二分法
149    * @param String ip字符串0.0.0.0到255.255.255.255
150    * @return long ip所在位置
151    */
152    public long seekIp(String ip) {
153        long tmp = StingIpToLong(ip);
154        long i=0;
155        long j=ipSum;
156        long m = 0;
157        long lm=0L;
158        while(i<j) {
159            m = (i+j)/2;
160            lm = m*RECORD_LENGTH + ipBegin;
161            if( tmp == byteArrayToLong(readBytes(lm, 4))){       
162                return byteArrayToLong(readBytes(3));
163            }else if(j==(i+1)) {
164                return byteArrayToLong(readBytes(3));
165            }else if( tmp > byteArrayToLong(readBytes(lm, 4))){
166                i = m;
167            }else/* if( tmp < byteArrayToLong(readBytes(lm, 4)))*/{
168                j = m;
169            }
170        }
171        System.out.println("没有找到ip");
172        return -1L;
173    }
174    private String readArea(long offset) throws IOException {
175        ipFile.seek(offset);
176        byte b = ipFile.readByte();
177        if(b == 0x01 || b == 0x02) {
178            long areaOffset =byteArrayToLong(readBytes(offset+1,3)); 
179        //   if(areaOffset == 0)
180        //       return "未知";
181        //   else
182                return readString(areaOffset);
183        } else
184            return readString(offset);
185    }
186    /**
187    * 通过ip位置获取国家地区,
188    * 参照纯真ip数据库结构
189    * @param offset
190    * @return 国家+地区
191    */
192    private String seekCountryArea(long offset) {
193            try {
194            ipFile.seek(offset + 4);
195            byte b = ipFile.readByte();
196            if(b == AREA_FOLLOWED) 
197            {
198                long countryOffset = byteArrayToLong(readBytes(3));
199                ipFile.seek(countryOffset);
200                b = ipFile.readByte();
201                if(b == NO_AREA) {
202                    country = readString(byteArrayToLong(readBytes(3)));
203                    ipFile.seek(countryOffset + 4);
204                } else
205                    country = readString(countryOffset);
206                //area = readArea(ipFile.getFilePointer());
207            } else if(b == NO_AREA) {
208                country = readString(byteArrayToLong(readBytes(3)));
209               // area = readArea(offset + 8);       
210            } else {
211                country = readString(ipFile.getFilePointer() - 1);
212                //area = readArea(ipFile.getFilePointer());
213            }
214            return readText(country,"省(.+?)市");//+" "+area;
215        } catch (IOException e) {
216            return null;
217        }
218    }
219    
220    /**  
221     * 正则表达式解析数据
222     * @param result  
223     * @identifier  
224     * @return  
225     */  
226    public static String readText(String result, String identifier) {   
227        Pattern shopNumberPattern = Pattern.compile(identifier);   
228        Matcher shopNamMatcher = shopNumberPattern.matcher(result);   
229        if (shopNamMatcher.find())   
230            return shopNamMatcher.group(1);   
231        return "";   
232    } 
233 
234    /**
235    * 从offset偏移处读取一个以0结束的字符串
236    * @param offset
237    * @return ret 读取的字符串,出错返回空字符串
238    */
239    private String readString(long offset){
240        try {
241            ipFile.seek(offset);
242            byte[] b = new byte[128];
243            int i;
244            for(i=0; (b.length != i) && ((b[i]=ipFile.readByte()) != 0); i++);
245            String ret = new String(b, 0 , i/*, "GBK"*/);
246            ret = ret.trim();
247            return (ret.equals("") ||
248                           ret.indexOf("CZ88.NET") != -1 )?"未知":ret;
249        } catch (IOException e) {
250            System.out.println("读取文件失败_readString");
251        }
252        return "";
253    }
254 
255    /**
256    * 包含字符串的ip记录
257    * @param addr 地址
258    * @return IpRecord ip记录
259    */
260    
261    public ArrayList<IpRecord> stringToIp(String addr) {
262        ArrayList<IpRecord> ret = new ArrayList<IpRecord>();
263        try{
264            FileChannel fc = ipFile.getChannel();
265            MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());
266            mbb.order(ByteOrder.LITTLE_ENDIAN);
267            //上面3代码未使用,内存映射文件功能未写
268 
269            for(long i = ipBegin+4; i != ipEnd+4; i += RECORD_LENGTH) {
270                String sca = seekCountryArea(byteArrayToLong(readBytes(i, 3)));       
271                if(sca.indexOf(addr) != -1) {
272                    IpRecord rec = new IpRecord();
273                    rec.address = sca;
274                    rec.beginIp= byteArrayToStringIp(readBytes(i-4,4));
275                    rec.endIp= byteArrayToStringIp(readBytes(i+3,4));
276                    ret.add(rec);
277                } 
278            }
279        } catch (IOException e) {
280            System.out.println(e.getMessage());
281        }
282        return ret;
283    }
284 
285    /**
286    * 封装ip记录,包括开始ip,结束ip和地址
287    */
288    private class IpRecord {
289        public String beginIp;
290        public String endIp;
291        public String address;
292 
293        public IpRecord() {
294            beginIp = endIp = address = "";   
295        }
296 
297        public String toString() {
298            return beginIp + " - " + endIp + " " + address;
299        }
300    }
301 
302    /**
303    * @return 单一实例
304    */
305    public static IpAddress getInstance() {
306        return instance;
307    }
308 
309    /**
310    * @param ip
311    * @return ret
312    */
313    public String IpStringToAddress(String ip) {
314        //这里要添加ip格式判断
315        //public boolean isIP(Strin ip)
316        long ipOffset = seekIp(ip);
317        String ret = seekCountryArea(ipOffset);
318        return ret;
319    }
320 
321    /**
322    * @return IpSum
323    */
324    public long getIpSum() {
325        return ipSum;
326    }
327 
328    public static void main(String[] args) throws UnknownHostException {
329        IpAddress ipAddr = IpAddress.getInstance();
330        //ip总数
331        long l = ipAddr.getIpSum();
332        System.out.println(l);
333        //纯真ip数据更新时间
334        String str = ipAddr.IpStringToAddress("255.255.255.0");
335        System.out.println(str);
336        
337        //测试
338        str = ipAddr.IpStringToAddress("222.88.59.214");
339        System.out.println(str);
340        str = ipAddr.IpStringToAddress("222.248.70.78");
341        System.out.println(str);
342        str = ipAddr.IpStringToAddress("188.1.255.255");
343        System.out.println(str);
344        str = ipAddr.IpStringToAddress("220.168.59.166");
345        System.out.println(str);
346        str = ipAddr.IpStringToAddress("221.10.61.90");
347        System.out.println(str);
348        InetAddress inet = InetAddress.getLocalHost(); 
349        System.out.println("本机的ip=" + inet.getHostAddress()); 
350    /*   java.net.InetAddress addr = null;
351        try{
352            addr = java.net.InetAddress.getLocalHost();
353        }catch(java.net.UnknownHostException e){
354            e.printStackTrace();
355        }
356        String ip=addr.getHostAddress().toString();//获得本机IP
357        System.out.print(ip);
358        String address=addr.getHostName().toString();//获得本机名称
359        System.out.print(address);
360        str = ipAddr.IpStringToAddress(ip);
361        System.out.println(str);*/
362 
363 
364        ArrayList<IpRecord> al = ipAddr.stringToIp("网吧");
365        Iterator it = al.iterator();
366 
367        File f = new File("ipdata.txt");
368        try{
369        if(!f.exists()) {
370            f.createNewFile();
371        }
372        BufferedWriter out = new BufferedWriter(
373                new OutputStreamWriter(
374                    new FileOutputStream(f, true)
375                    )
376                );
377        int i=0;
378        while(it.hasNext()) {
379            out.write(it.next().toString());
380            out.newLine();
381            i++;
382        }
383        out.write(new Date().toString());
384        out.write("总共搜索到 "+i);
385        out.close();
386        }catch(IOException e){
387            e.printStackTrace();
388        }
389 
390    }   
391 } 

自己在网上在去下载个qqwry.dat放到根目录下就好

posted on 2013-10-30 16:18  sun&flower  阅读(2131)  评论(0编辑  收藏  举报