第一部分 : 案例概述 : (需要access.log 和 ip.txt 虚拟文件)
给定的access.log是电信运营商的用户上网数据,第一个字段是时间, 第二个字段是ip地址,第三个字段是访问的网站,其他字段可以忽略不计.
ip.txt是ip地址和归属地的规则数据,里面的数据是根据ip地址的十进制从低到高排序。
第一个字段是网段的起始IP地址,
第二个字段是网段的结束IP地址,
第三个字段是网段的起始IP地址对应的十进制,
第四个字段是网段的结束IP地址对应的十进制,
第五个字段代表洲,
第六个代表国家,
第七个代表省,
第八个代表城市,
第九个区域,
第十个运营商。
其他字段可以忽略不计。
要求:
通过计算access.log中的用户行为数据,统计出各个省份访问量(一次请求记作一次独立的访问量),并按照各个省份的访问量的从高到低进行排序
步骤分析
根据Log数据获取所有的ip数据 根据ip去ip的规则数据中查询区域或者运营商数据
1 读取ip规则数据 将每条数据封装在bean里面 把所有的数据封装在list中
2 将ip转成长整型数据
3 使用二分查找查IpBean —–> 结果集 Map
代码实现 :
第二部分 : 代码实现
1.用IpBean来封装数据;
package com.doit.examle3;
public class IpBean {
// 1.0.8.0|1.0.15.255|16779264|16781311|亚洲|中国|广东|广州||电信
private String startIp;
private String endIp;
private Long startLongIp;
private Long endLongIp;
/** 洲 */
private String zhou;
private String country;
private String province;
private String city;
private String area;
/** 运营商 */
private String isp;
public void set(String startIp, String endIp, Long startLongIp, Long endLongIp, String zhou, String country,
String province, String city, String area, String isp) {
this.startIp = startIp;
this.endIp = endIp;
this.startLongIp = startLongIp;
this.endLongIp = endLongIp;
this.zhou = zhou;
this.country = country;
this.province = province;
this.city = city;
this.area = area;
this.isp = isp;
}
public String getStartIp() {
return startIp;
}
public void setStartIp(String startIp) {
this.startIp = startIp;
}
public String getEndIp() {
return endIp;
}
public void setEndIp(String endIp) {
this.endIp = endIp;
}
public Long getStartLongIp() {
return startLongIp;
}
public void setStartLongIp(Long startLongIp) {
this.startLongIp = startLongIp;
}
public Long getEndLongIp() {
return endLongIp;
}
public void setEndLongIp(Long endLongIp) {
this.endLongIp = endLongIp;
}
public String getZhou() {
return zhou;
}
public void setZhou(String zhou) {
this.zhou = zhou;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getIsp() {
return isp;
}
public void setIsp(String isp) {
this.isp = isp;
}
@Override
public String toString() {
return "IpBean [startIp=" + startIp + ", endIp=" + endIp + ", startLongIp=" + startLongIp + ", endLongIp="
+ endLongIp + ", zhou=" + zhou + ", country=" + country + ", province=" + province + ", city=" + city
+ ", area=" + area + ", isp=" + isp + "]";
}
}
2.写一个工具类 : IpUtils
package com.doit.examle3;
import java.util.List;
public class IpUtils {
/**
* 使用静态代码块来初始化list<IpBean>
*/
static List<IpBean> list = null;
static {// static确保只读一次
try {
list = ReadIp.getIpInfo();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据字符串ip返回IpBean
*
* @param ip
* @return
*/
public static IpBean getIpBean(String ip) {
long ipLong = paseIpToLong(ip);
// 二分查找
int left = 0;
int right = list.size() - 1;
int middle;
while (left <= right) {
middle = (left + right) / 2;//middle的计算必须放在while循环体内,这样才能保证每次的引用偏移
IpBean ipBean = list.get(middle);
Long startLongIp = ipBean.getStartLongIp();
Long endLongIp = ipBean.getEndLongIp();
if (ipLong < startLongIp) {
right = middle - 1;
}
if (ipLong > endLongIp) {
left = middle + 1;
}
if (ipLong >= startLongIp && ipLong <= endLongIp) {
return ipBean;
}
}
return null;
}
/**
* 把字符串ip转成long值
*
* @param ip
* 要转的字符串ip
* @return
*/
public static long paseIpToLong(String ip) {
long newIP = 0l;
if (ip == null) {
return newIP;
}
String[] split = ip.split("\\.");
if (split.length == 4) {
for (int i = 0; i < split.length; i++) {
long l = Long.parseLong(split[i]);
newIP |= l << ((3 - i) << 3);
}
}
return newIP;
}
}
3.处理 ip.txt 文件
package com.doit.examle3;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ReadIp {
/**
* 封装数据 : 把ip的信息封装到IpBean,然后把IpBean放入到List<IpBean>,可以对list进行排序
*
* @return
* @throws Exception
*/
public static List<IpBean> getIpInfo() throws Exception {
List<IpBean> list = new ArrayList<>();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:/data/y/ip.txt"), "UTF-8"));
String line = null;
while ((line = br.readLine()) != null) {
// 对读取的每行数据做业务处理 : 用 "\|" 切割
String[] split = line.split("\|");
// 把数据封装到IpBean
String startIp = split[0];
String endIp = split[1];
Long startLongIp;
Long endLongIp;
try {
startLongIp = Long.parseLong(split[2]);
endLongIp = Long.parseLong(split[3]);
} catch (Exception e) {// 过滤"坏数据"
continue;
}
String zhou = split[4];
String country = split[5];
String province = split[6];
String city = split[7];
String area = split[8];
String isp = split[9];
IpBean bean = new IpBean();
bean.set(startIp, endIp, startLongIp, endLongIp, zhou, country, province, city, area, isp);
// 把bean存放到List<IpBean>
list.add(bean);
}
br.close();
return list;
}
}
4.处理 access.log 文件
package com.doit.examle3;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class ReadLog {
/**
* 根据日志文件获取结果map : (k,v)<-->Map<String, Integer>(省份, 该省的访问量)
*
* @return
* @throws Exception
*/
public static Map<String, Integer> getLogInfo() throws Exception {
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> resMap = new LinkedHashMap<>();// 使用LinkedHashMap来接收排序结果
BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream("D:/data/y/access.log"), "UTF-8"));
// 读取日志文件
String line = null;
while ((line = br.readLine()) != null) {
// 对读取的每行数据做业务处理 :
String[] split = line.split("\|");
// 获取ip
String ip = split[1];
/**
* 根据ip获取IpBean
*/
IpBean ipBean = IpUtils.getIpBean(ip);
String p = ipBean.getProvince();
Integer count = map.getOrDefault(p, 0);// 获取每个省份的访问量
map.put(p, ++count);
}
/**
* 按照访问量从高低低排序,并放入LinkedHashMap
*/
Set<Entry<String, Integer>> entrySet = map.entrySet();
ArrayList<Entry<String, Integer>> list = new ArrayList<>(entrySet);
Collections.sort(list, (o1, o2) -> o2.getValue() - o1.getValue());
// 遍历排好序的list,放入resMap
for (Entry<String, Integer> entry : list) {
resMap.put(entry.getKey(), entry.getValue());
}
br.close();
return resMap;
}
}
*5.测试类*
package com.doit.examle3;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class TestMain {
public static void main(String[] args) throws Exception {
Map<String, Integer> map = ReadLog.getLogInfo();
Set<Entry<String, Integer>> entrySet = map.entrySet();
for (Entry<String, Integer> entry : entrySet) {
System.out.println(entry);
}
}
}