项目介绍
- 背景
根据IP得到位置,加标签
进行大数据分析,比如淘宝推荐等提供优质数据
www.ip.cn 等 查询IP
- 需求
IP 分析 归属地信息 , 查找在毫秒内完成
IP地址库,公网都是开放的
IANA : 国际组织,负责公网IP维护分发
- 技术栈
Eclipse ,JavaSE中面向对象、IO流、二分法算法、Base64编码、工具类封装
- 目标
通过开发IP地址归属地查询平台,我们需要对JavaSE综合技术有所提升,增强实战能力。学习完该项目我们应该具备如下能力:
1 面向对象程序设计
2 工具类封装与使用写法
3 文件IO流
4 字符串处理
5 二分法查找
6 IP地址的不同形式的使用
- 相关问题
强化项目思维
不管好方法还是差方法,先尝试把功能实现
再考虑对代码进行优化,最优为止
- 主要思路
1 解析提供的地址库字符串,为结构化数据格式
2 基于结构化数据构建成某个数据结构,加速给定IP地址的查找速度
3 封装成响应的工具类API,开放其响应的方法,即给定IP地址可以再ms内计算得到其位置信息
4 工具类只有一个入参一个出参
入参是IP
出参是地址
- 研发项目分类
1 应用开发类项目
解决某些特定功能而开发的应用软件,比如QQ,微信,Eclipse等
2 Web开发类 项目
以B/S架构为主,也就是网页形式访问的在线系统,如各类官网等
3 中小型应用类开发项目的流程
1 需求概述 : 需求描述,说清楚你要干什么,为什么做这个
在互联网公司中,根据IP地址获取归属地信息是非常广泛的,开发的这个项目就能解决这个问题
2 需求分析 : 需要根据需求概述,用技术角度来看一下这个项目是否可行
可行性一定是可以做的
需求分析的梳理
三方面 : 输入,输出,已具备的物料(前置条件)
输入 : 给定任意一个IP地址
输出 : 返回IP对应的归属地
前置条件 :
IP地址库
JavaSE
面向对象
IO
常用类
二分法
正则表达式校验
3 开发步骤拆分,可以理解为解耦,把一个拆分为多个
1 读取IP地址库
2 解析IP地址每行数据,进行结构化
找到无结构化数据的规则,进行结构化处理
简单来说,就是根据需求,生成实体类
Entity/model : 实体类,一般该类和数据库表是一一对应的
DTO : 先不管
Pojo : 无特殊意义,纯粹的业务对象
3 把对象加入List中
4 转换为数组,方便二分法操作
为什么不直接转换为数组?
数组长度问题,不清楚有多少行,有多少空行等
ArrayList转数组,不会消耗很多时间,因为底层就是数组
5 解决二分法查找的技术问题
6 完成比较逻辑
7 对外提供访问接口
8 测试
4 细节开发与风险控制
5 BUG修复,调优,标准化
6 正式上线
7 项目总结,项目复盘
- 代码研发
- 无脑读取文件
在test文件夹下 创建 TestFileIO_01.java
package com;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
/**
* 1 定义文件路径
*
* 2 通过节点流对接到文本上
*
* 3 将节点流转换为字符流
*
* 4 通过缓冲流对接到输入流
*
* 5 读取
*
* 6 关闭流
*
*/
public class TestFileIO_01 {
public static void main(String[] args) {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
try (
// 字节流
FileInputStream fis = new FileInputStream(ipLibrartPath);
// 转换为字符流
Reader reader = new InputStreamReader(fis, encoding);
// 封装缓冲流
BufferedReader br = new BufferedReader(reader);) {
String temp = null;
while ((temp = br.readLine()) != null) {
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 文本文件读取工具类
工具类封装 :
1 先写测试类,确认输入与输出技术问题
2 抽象出了输入与输出,形成方法的入参和出参
3 工具代码实现,测试
-
- 工具类
package com.tledu.zrz.util;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* 读取文件
*
*/
public class FileOperatorUtil {
/**
* 读取文件,并返回List
*
* @param txtFilePath
* 字符串格式的文件路径
* @param encoding
* 字符编码
* @return
* @throws IOException
*/
public static List<String> getLineList(String txtFilePath, String encoding)
throws IOException {
List<String> lineLine = new ArrayList<String>();
// 字节流
FileInputStream fis = new FileInputStream(txtFilePath);
// 转换为字符流
Reader reader = new InputStreamReader(fis, encoding);
// 封装缓冲流
BufferedReader br = new BufferedReader(reader);
String temp = null;
while ((temp = br.readLine()) != null) {
lineLine.add(temp);
}
// 关闭资源
br.close();
return lineLine;
}
}
-
- 测试工具类
package com;
import java.io.IOException;
import java.util.List;
import com.tledu.zrz.util.FileOperatorUtil;
/**
* 测试工具类
*/
public class TestFileIO_02 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
for (String string : lineList) {
System.out.println(string);
}
}
}
- 数据结构化
1 可以找无结构化数据的组织规则,进行抽象,转换为结构化
2 根据数据组织进行数据抽象
3 解析数据,保存到对应的对象中
Model,pojo,dto
- 抽象pojo类
- 抽象封装
package com.tledu.zrz.pojo;
/**
* 结构化实体类
*
*/
public class IPAndLocationPojo {
@Override
public String toString() {
return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP
+ ", location=" + location + "]";
}
/**
* 起始IP
*/
private String startIP;
/**
* 结束IP
*/
private String endIP;
/**
* 归属地
*/
private String location;
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 String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public IPAndLocationPojo(String startIP, String endIP, String location) {
super();
this.startIP = startIP;
this.endIP = endIP;
this.location = location;
}
public IPAndLocationPojo() {
super();
}
}
-
- 数据拆分,转换为对象
package com;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
/**
* 转换为结构化对象
*/
public class TestNonStructToStruct_01 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
// 遍历集合
for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojos) {
System.out.println(ipAndLocationPojo);
}
}
}
- 封装DataProcessManager类
- 把数据封装到对象中并保存list里面
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
-
- 测试
package com;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.tledu.zrz.manager.DataProcessManager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
/**
* 转换为结构化对象
*/
public class TestNonStructToStruct_02 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath, encoding);
for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojos) {
System.err.println(ipAndLocationPojo);
}
}
}
- 结构化集合转换为数组
package com;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.tledu.zrz.manager.DataProcessManager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
public class TestListToArray_01 {
public static void main(String[] args) throws IOException {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
String[] arr = new String[list.size()];
list.toArray(arr);
for (String string : arr) {
System.out.println(string);
}
// 业务数据
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager
.getPojoList(ipLibrartPath, encoding);
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[ipAndLocationPojos
.size()];
ipAndLocationPojos.toArray(ipLocationPojoArr);
for (IPAndLocationPojo ipAndLocationPojo : ipLocationPojoArr) {
System.out.println(ipAndLocationPojo);
}
}
}
- 对象数组排序
- 实现排序
1 自定义实现
冒泡,选择
2 API
Collections,Arrays
-
- 排序注意事项
1 被排序的元素必须具有可比性
实现Comparable接口
有比较器类Comparator
-
- 排序案例
package com;
import java.util.Arrays;
public class TestArrySort_01 {
public static void main(String[] args) {
// 数字 : 从小到大
// 字符串 : ASCII码
// 日期 : 自然日期
// 因为 Integer,String,Date 都实现了Comparable接口
int[] intArray = { 1, 13, 24, 7, 4 };
Arrays.sort(intArray);
for (int i : intArray) {
System.out.println(i);
}
A a1 = new A(18, "张三1");
A a2 = new A(19, "张三2");
A a3 = new A(15, "张三3");
A a4 = new A(12, "张三4");
A[] a = { a1, a2, a3, a4 };
Arrays.sort(a);
for (A a5 : a) {
System.out.println(a5);
}
}
}
class A implements Comparable<A>{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public A(int age, String name) {
super();
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "A [age=" + age + ", name=" + name + "]";
}
@Override
public int compareTo(A o) {
return age-o.age;
}
}
-
- 总结
要么实现排序的类 实现Comparable接口
-
- 业务问题
由于IP是字符串,而字符串比较ASCII码
比如 1.1.6.32 , 1.1.128.23 理论上应该是后面的大
但是按照ASCII码比较的话,前面的大
所以我们需要把IP转换为long类型进行比较即可
package com.tledu.zrz.util;
/**
* IP和long类型之间的转换
*
*/
public class IPUtil {
public static void main(String[] args) {
long x = ipToLong("120.211.144.131");
System.out.println(x);
String s = longToIp(x);
System.out.println(s);
}
private static Long ipToLong(String ipStr) {
long ipLong = 0;
if (ipStr != null && ipStr.length() > 0) {
// 将ip(点分十进制的形式 a.b.c.d) 地址按.分割
String[] ipSplit = ipStr.split("\\.");
try {
if (ipSplit.length != 4) {
throw new Exception("IP Format Error");
}
for (int i = 0; i < ipSplit.length; i++) {
int temp = Integer.parseInt(ipSplit[i]);
ipLong += temp * (1L << (ipSplit.length - i - 1) * 8);
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
}
return ipLong;
}
/**
* 将long型IP地址转换回点分十进制表示的字符串类型
*
* @param ipLong
* @return java.lang.String
* @throws Exception
*/
private static String longToIp(long ipLong) {
StringBuffer ipStr = new StringBuffer();
try {
if (ipLong < 0) {
throw new Exception("Can not to IP...");
}
// 最高8位,直接右移24位
ipStr.append((ipLong >>> 24));
ipStr.append(".");
// 将高8位设置0,然后右移16位
ipStr.append(((ipLong & 0x00FFFFFF) >>> 16));// 获得高8位,6个f对应的是24个1,最高8位设置空为0,之后右移16位将前面多余的16位去掉,以下类推即可
ipStr.append(".");
// 将高16位设置0,然后右移8位
ipStr.append((ipLong & 0x0000FFFF) >>> 8); // 前16位
// 设置0,移除低8位,16个1,高16位设置为0
ipStr.append(".");
// 将高24位设置0
ipStr.append(ipLong & 0x000000FF); // 前24位 设置0,留低8位,8个1,高24位设置为0
} catch (Exception e) {
e.printStackTrace();
}
return ipStr.toString();
}
}
-
- Pojo添加衍生字段
实体类中衍生两个字段,用来存储转换为long类型之后的值
package com.tledu.zrz.pojo;
import com.tledu.zrz.util.IPUtil;
/**
* 结构化实体类
*
*/
public class IPAndLocationPojo implements Comparable<IPAndLocationPojo> {
@Override
public String toString() {
return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP
+ ", location=" + location + "]";
}
/**
* 起始IP
*/
private String startIP;
// 衍生字段
private long startIPLong;
private long endIPLong;
/**
* 结束IP
*/
private String endIP;
public long getStartIPLong() {
return startIPLong;
}
public void setStartIPLong(long startIPLong) {
this.startIPLong = startIPLong;
}
public long getEndIPLong() {
return endIPLong;
}
public void setEndIPLong(long endIPLong) {
this.endIPLong = endIPLong;
}
/**
* 归属地
*/
private String location;
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 String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public IPAndLocationPojo(String startIP, String endIP, String location) {
super();
this.startIP = startIP;
this.endIP = endIP;
this.location = location;
this.startIPLong = IPUtil.ipToLong(startIP);
this.endIPLong = IPUtil.ipToLong(endIP);
}
public IPAndLocationPojo() {
super();
}
@Override
public int compareTo(IPAndLocationPojo o) {
// 因为IP段没有交集,所以使用起始和结束 比较 都是可以的
long result = startIPLong - o.startIPLong;
if (result > 0) {
return 1;
} else if (result < 0) {
return -1;
} else {
return 0;
}
}
}
-
- 测试Pojo排序
package com;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import com.tledu.zrz.manager.DataProcessManager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
public class TestArrySort_02 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager
.getPojoList(ipLibrartPath, encoding);
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[ipAndLocationPojos
.size()];
ipAndLocationPojos.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
// 测试首位元素
System.out.println(ipLocationPojoArr[0]);
System.out.println(ipLocationPojoArr[ipLocationPojoArr.length-1]);
}
}
-
- 封装排序
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
public static IPAndLocationPojo[] convertListToArrayAndSort(
List<IPAndLocationPojo> pojoList) {
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
-
- 测试
package com;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import com.tledu.zrz.manager.DataProcessManager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
public class TestArrySort_03 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager
.getPojoList(ipLibrartPath, encoding);
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager.convertListToArrayAndSort(ipAndLocationPojos);
// 测试首位元素
System.out.println(ipLocationPojoArr[0]);
System.out.println(ipLocationPojoArr[ipLocationPojoArr.length-1]);
}
}
- 二分法
二分法查询,必须建立在已排序的基础上
-
- 基本类型
public static void main(String[] args) {
// 基础类型
int[] intArray = {1,3,5,7,9,11,100,900};
int aid = 9200;
int startIndex = 0;
int endIndex = intArray.length-1;
int m = (endIndex+startIndex)/2;
while (startIndex <= endIndex) {
if (aid == intArray[m]) {
System.out.println(m);
return;
}else if (aid > intArray[m]) {
startIndex = m+1;
}else{
endIndex = m -1;
}
m=(startIndex+endIndex)/2;
}
System.out.println("没找着");
}
-
- 引用/复杂类型
public static void main(String[] args) {
User u1 = new User(18);
User u2 = new User(19);
User u3 = new User(20);
User u4 = new User(21);
User u5 = new User(22);
// 复杂类型
User[] intArray = { u1, u2, u3, u4, u5 };
int aid = 23;
int startIndex = 0;
int endIndex = intArray.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
if (aid == intArray[m].getAge()) {
System.out.println(m);
return;
} else if (aid > intArray[m].getAge()) {
startIndex = m + 1;
} else {
endIndex = m - 1;
}
m = (startIndex + endIndex) / 2;
}
System.out.println("没找着");
}
-
- 业务类实现
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager
.getPojoList(ipLibrartPath, encoding);
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
// 用户输入的IP
// String aid = "125.152.1.22";
String aid = "120.211.144.131";
// 转换为long类型
long ipLong = IPUtil.ipToLong(aid);
int startIndex = 0;
int endIndex = ipLocationPojoArr.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
// 大于等于起始 小于等于结束 说明找到了
// 小于起始 在前半截
// 大于结束 在后半截
if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {
startIndex = m + 1;
} else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {
endIndex = m - 1;
} else {
System.out.println(ipLocationPojoArr[m]);
return;
}
m = (startIndex + endIndex) / 2;
}
System.out.println("没找着");
}
- IP地址对象的范围形式数据的二分法实现
- 业务类功能实现
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import com.tledu.zrz.util.IPUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
/**
* 业务类对应的二分法
*
* @param ipLocationPojoArr
* 数组
* @param ip
* ip
* @return 索引
*/
public static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,
String ip) {
// 转换为long类型
long ipLong = IPUtil.ipToLong(ip);
int startIndex = 0;
int endIndex = ipLocationPojoArr.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
// 大于等于起始 小于等于结束 说明找到了
// 小于起始 在前半截
// 大于结束 在后半截
if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {
startIndex = m + 1;
} else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {
endIndex = m - 1;
} else {
return m;
}
m = (startIndex + endIndex) / 2;
}
return -1;
}
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
public static IPAndLocationPojo[] convertListToArrayAndSort(
List<IPAndLocationPojo> pojoList) {
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
-
- 测试
package com;
import java.io.IOException;
import java.util.List;
import com.tledu.zrz.manager.DataProcessManager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.IPUtil;
public class TestBinaraySearch_02 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager
.getPojoList(ipLibrartPath, encoding);
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
// 用户输入的IP
String ip = "125.152.1.22";
// String ip = "120.211.144.131";
int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);
System.out.println(ipLocationPojoArr[index]);
}
}
- 工具类封装
到目前为止,已经把二分法搞定了,已经可以实现功能了,测试代码就相当于客户端
但是目前客户端知道的信息还是比较多,客户只关心 入参和出参是什么就可以
至于我们用什么编码,用什么存储,客户根本不关心
此时我们需要提供一个对外访问的方法,该方法入参就是IP 出参就是归属地
-
- 编码
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import com.tledu.zrz.util.IPUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
/**
* 对外提供的接口,入参IP出参地址
*
* @param ip
* @return
*/
public static String getLocation(String ip) {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = null;
try {
ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,
encoding);
} catch (IOException e) {
e.printStackTrace();
}
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);
return ipLocationPojoArr[index].getLocation();
}
/**
* 业务类对应的二分法
*
* @param ipLocationPojoArr
* 数组
* @param ip
* ip
* @return 索引
*/
private static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,
String ip) {
// 转换为long类型
long ipLong = IPUtil.ipToLong(ip);
int startIndex = 0;
int endIndex = ipLocationPojoArr.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
// 大于等于起始 小于等于结束 说明找到了
// 小于起始 在前半截
// 大于结束 在后半截
if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {
startIndex = m + 1;
} else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {
endIndex = m - 1;
} else {
return m;
}
m = (startIndex + endIndex) / 2;
}
return -1;
}
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
private static IPAndLocationPojo[] convertListToArrayAndSort(
List<IPAndLocationPojo> pojoList) {
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
private static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
-
- 测试
package com;
import java.io.IOException;
import com.tledu.zrz.manager.DataProcessManager;
public class TestBinaraySearch_03 {
public static void main(String[] args) throws IOException {
// String ip = "125.152.1.22";
String ip = "120.211.144.131";
String location = DataProcessManager.getLocation(ip);
System.out.println(location);
}
}
-
- 优化
功能实现了,像以下情况,同一个生命周期中,如果操作两次及两次以上
那么 会导致 ip_location_relation地址库被解析多次,并且结构化多次,并且排序多次
带来的性能变弱
因为在一个生命周期当前,只解析一次,结构化一次,排序一次即可,每次获取归属地的时候,只需要进行二分法操作即可
可以使用静态代码块解决
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import com.tledu.zrz.util.IPUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 该类为项目中管理类
*/
public class DataProcessManager {
private static IPAndLocationPojo[] ipLocationPojoArr = null;
static {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = null;
try {
ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,
encoding);
} catch (IOException e) {
e.printStackTrace();
}
// 转换为数组
ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
}
/**
* 对外提供的接口,入参IP出参地址
*
* @param ip
* @return
*/
public static String getLocation(String ip) {
int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);
return ipLocationPojoArr[index].getLocation();
}
/**
* 业务类对应的二分法
*
* @param ipLocationPojoArr
* 数组
* @param ip
* ip
* @return 索引
*/
public static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,
String ip) {
// 转换为long类型
long ipLong = IPUtil.ipToLong(ip);
int startIndex = 0;
int endIndex = ipLocationPojoArr.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
// 大于等于起始 小于等于结束 说明找到了
// 小于起始 在前半截
// 大于结束 在后半截
if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {
startIndex = m + 1;
} else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {
endIndex = m - 1;
} else {
return m;
}
m = (startIndex + endIndex) / 2;
}
return -1;
}
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
public static IPAndLocationPojo[] convertListToArrayAndSort(
List<IPAndLocationPojo> pojoList) {
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
-
- 测试
- 入口类
package com.tledu.zrz.controller;
import java.util.Scanner;
import com.tledu.zrz.manager.DataProcessManager;
/**
* 程序入口
*
*/
public class SystemController {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入IP : ");
String ip = scanner.nextLine();
long startTime = System.currentTimeMillis();
String location = DataProcessManager.getLocation(ip);
long endTime = System.currentTimeMillis();
System.out.println(location + " : " + (endTime - startTime));
}
}
}
- BUG优化
用户输入 需要严格校验,比如IP地址不正确,还有必要去查询吗?
-
- 技术问题
正则表达式
Pattern和Matcher
Pattern是正则表达式引擎
Matcher是匹配器
Matches : 全词匹配
Find : 任意位置
lookingAt : 从前往后匹配
package com;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestRegex_01 {
public static void main(String[] args) {
String regex = "\\d{11}";
String tel = "131131131121";
// 创建引擎
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(tel);
// System.out.println(matcher.matches());
// System.out.println(matcher.find());
System.out.println(matcher.lookingAt());
tel = "我的电话是13113113111";
regex = "我的电话是(\\d{11})";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(tel);
matcher.find();
System.out.println(matcher.group(1));
}
}
-
- 封装工具类
package com.tledu.zrz.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式工具类
*
*/
public class RegexUtil {
/**
* 格式验证
*
* @param regex
* @param input
* @return
*/
public static boolean isValid(String regex, String input) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
/**
* 数据提取
*
* @param regex
* @param input
* @param groupIndex
* @return
*/
public static String getMatchContent(String regex, String input,
int groupIndex) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher.group(groupIndex);
}
return null;
}
public static String getMatchContent(String regex, String input) {
return getMatchContent(regex, input, 0);
}
}
-
- 测试工具类
package com;
import com.tledu.zrz.util.RegexUtil;
public class TestRegex_02 {
public static void main(String[] args) {
String regex = "\\d{11}";
String tel = "13113113111";
System.out.println(RegexUtil.isValid(regex, tel));
tel = "我的电话是13113113111";
regex = "我的电话是(\\d{11})";
System.out.println(RegexUtil.getMatchContent(regex, tel,1));
}
}
-
- 业务问题
package com.tledu.zrz.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式工具类
*
*
*/
public class RegexUtil {
private static String regexIP = "((25[0-5]|2[0-4]\\d|[1]{1}\\d{1}\\d{1}|[1-9]{1}\\d{1}|\\d{1})($|(?!\\.$)\\.)){4}";
/**
* 校验IP
* @param ip
* @return
*/
public static boolean isValidIP(String ip) {
return isValid(regexIP, ip);
}
/**
* 格式验证
*
* @param regex
* @param input
* @return
*/
public static boolean isValid(String regex, String input) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}
/**
* 数据提取
*
* @param regex
* @param input
* @param groupIndex
* @return
*/
public static String getMatchContent(String regex, String input,
int groupIndex) {
Pattern pattern = Pattern.compile(regex);
// 创建匹配器
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher.group(groupIndex);
}
return null;
}
public static String getMatchContent(String regex, String input) {
return getMatchContent(regex, input, 0);
}
}
-
- 测试
package com;
import com.tledu.zrz.util.RegexUtil;
public class TestRegex_03 {
public static void main(String[] args) {
String ip = "1.1.322.5";
System.out.println(RegexUtil.isValidIP(ip));
}
}
-
- 应用
校验应该写在对外提供的接口处
getLocation
- 性能调优
- 相关技术
- 硬件
- 相关技术
内存,CPU.磁盘,网络等 都可以实现性能提
- 软件
- 直接调优
哪里慢,就调哪里,不需要花里胡哨的
主要指算法问题,内核层面,难度较大,大部分都是非直接调优
迂回调优
通过设计,策略,可以通过不用面对底层优化的难题
迂回调优方向
缓存策略
通过添加时间断点,测试得出,结构化耗时较多
一开始,我们一次运行中,先后校验两个IP,需要结构化两次
后来我们使用静态语句块解决了这个问题
做到一次生命周期中,只会结构化一次
现在面临的问题是,需要让多次生命周期,使用同一个结构化之后的对象,就可以解决当前的问题
可以使用序列化和反序列化解决
序列化和反序列化
序列化 : 将内存对象保存到硬盘中
反序列化 : 把硬盘中对象载入到内存
被序列化的对象必须实现serlizable接口
- 首次调优
- 技术问题
package com;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TestSerinalizable_01 {
public static void main(String[] args) throws Exception{
User user =new User(11);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/x"));
oos.writeObject(user);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/x"));
Object o = ois.readObject();
System.out.println(o);
}
}
class User implements Serializable{
private int age;
public User(int age) {
super();
this.age = age;
}
@Override
public String toString() {
return "User [age=" + age + "]";
}
}
-
-
- 封装工具类
-
package com.tledu.zrz.util;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerDeUtil {
/**
* 写入
*
* @param obj
* @param objFilePath
* @throws IOException
*/
public static void saveObject(Object obj, String objFilePath)
throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
objFilePath));
oos.writeObject(obj);
oos.close();
}
/**
* 读取
*
* @param objFilePath
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object getObj(String objFilePath)
throws ClassNotFoundException, IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
objFilePath));
Object o = ois.readObject();
return o;
}
}
-
-
- 测试
-
package com;
import com.tledu.zrz.util.SerDeUtil;
public class TestSerinalizable_02 {
public static void main(String[] args) throws Exception{
User user =new User(11);
SerDeUtil.saveObject(user, "D:/a");
System.out.println(SerDeUtil.getObj("D:/a"));
}
}
-
-
- 初始化优化
-
只有第一次才序列化,其余的都反序列化即可
判断该文件是否存在,如果存在,就反序列化获取,如果不存在,就序列化写出
注意
public class IPAndLocationPojo implements Serializable,
Comparable<IPAndLocationPojo> {
package com.tledu.zrz.manager;
import com.tledu.zrz.pojo.IPAndLocationPojo;
import com.tledu.zrz.util.FileOperatorUtil;
import com.tledu.zrz.util.IPUtil;
import com.tledu.zrz.util.RegexUtil;
import com.tledu.zrz.util.SerDeUtil;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
private static IPAndLocationPojo[] ipLocationPojoArr = null;
static {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 文件地址
String serde_obj_filepath = "ipLibObj.data";
// 判断序列化文件是否存在
boolean isInit = new File(serde_obj_filepath).exists();
// 存在就反序列化获取
if (isInit) {
try {
Object object = SerDeUtil.getObj(serde_obj_filepath);
ipLocationPojoArr = (IPAndLocationPojo[]) object;
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}else{
// 不存在就序列化写出
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = null;
try {
ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,
encoding);
} catch (IOException e) {
e.printStackTrace();
}
// 转换为数组
ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
try {
SerDeUtil.saveObject(ipLocationPojoArr, serde_obj_filepath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 对外提供的接口,入参IP出参地址
*
* @param ip
* @return
*/
public static String getLocation(String ip) {
if (RegexUtil.isValidIP(ip)) {
int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);
return index == -1 ? "未找到" : ipLocationPojoArr[index].getLocation();
}else{
return "IP地址格式不正确,请重新输入";
}
}
/**
* 业务类对应的二分法
*
* @param ipLocationPojoArr
* 数组
* @param ip
* ip
* @return 索引
*/
public static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,
String ip) {
// 转换为long类型
long ipLong = IPUtil.ipToLong(ip);
int startIndex = 0;
int endIndex = ipLocationPojoArr.length - 1;
int m = (endIndex + startIndex) / 2;
while (startIndex <= endIndex) {
// 大于等于起始 小于等于结束 说明找到了
// 小于起始 在前半截
// 大于结束 在后半截
if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {
startIndex = m + 1;
} else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {
endIndex = m - 1;
} else {
return m;
}
m = (startIndex + endIndex) / 2;
}
return -1;
}
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
public static IPAndLocationPojo[] convertListToArrayAndSort(
List<IPAndLocationPojo> pojoList) {
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List<String> 转换为 List<IPAndLocationPojo>
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,
String encoding) throws IOException {
List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,
encoding);
List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();
// 遍历 获取每一行
for (String string : lineList) {
if (string == null || string.trim().equals("")) {
continue;
}
// 以\t分割,得到三个列
String[] columnArray = string.split("\t");
// 创建结构化对象
IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(
columnArray[0], columnArray[1], columnArray[2]);
// 保存到集合中
ipAndLocationPojos.add(ipAndLocationPojo);
}
return ipAndLocationPojos;
}
}
-
- IO调优
加入序列化和反序列化之后,导致效率更低,并且第二个运行要比第一次还慢,说明反序列化有问题
缓冲流 : 缓冲流是IO流的缓冲区,用来提高IO的效率
首次 7000
非首次 20000
文件大小为 38.3M
-
-
- 引入缓冲流
-
package com.tledu.zrz.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerDeUtil {
/**
* 对象写出,引入缓冲流
*
* @param obj
* @param objFilePath
* @param cacheByyeArrayLength
* @throws IOException
*/
public static void saveObject(Object obj, String objFilePath,
int cacheByyeArrayLength) throws IOException {
FileOutputStream fos = new FileOutputStream(objFilePath);
// 字节数组缓冲流
ByteArrayOutputStream baos = new ByteArrayOutputStream(
cacheByyeArrayLength);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
byte[] bytes = baos.toByteArray();
fos.write(bytes);
oos.close();
fos.close();
}
/**
* 获取,引入缓冲流
*
* @param objFilePath
* @param cacheByyeArrayLength
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object getObj(String objFilePath, int cacheByyeArrayLength)
throws ClassNotFoundException, IOException {
FileInputStream fis = new FileInputStream(objFilePath);
byte[] bytes = new byte[cacheByyeArrayLength];
fis.read(bytes);
fis.close();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();
ois.close();
return o;
}
/**
* 写入
*
* @param obj
* @param objFilePath
* @throws IOException
*/
public static void saveObject(Object obj, String objFilePath)
throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
objFilePath));
oos.writeObject(obj);
oos.close();
}
/**
* 读取
*
* @param objFilePath
* @return
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object getObj(String objFilePath)
throws ClassNotFoundException, IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
objFilePath));
Object o = ois.readObject();
ois.close();
return o;
}
}
更改之后 首次 3000 非首次 1000
- 代码标准化
代码中,出现了好多这些变量,当我们需要更改某一个的时候,不好找
集中管理
- StaticValue
package com.tledu.zrz.util;
public class StaticValue {
// 地址库文件
public static String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
public static String encoding = "utf-8";
// 文件地址
public static String serde_obj_filepath = "ipLibObj.data";
// 根据文件大小,计算长度
public static int cacheByteArrayLength = 40*1024*1024;
}
- 应用
// 判断序列化文件是否存在
File file = new File(StaticValue.serde_obj_filepath);
boolean isInit = file.exists();
// 存在就反序列化获取
if (isInit) {
try {
Object object = SerDeUtil.getObj(
StaticValue.serde_obj_filepath,
StaticValue.cacheByteArrayLength);
ipLocationPojoArr = (IPAndLocationPojo[]) object;
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
} else {
// 不存在就序列化写出
// 获取数据
List<IPAndLocationPojo> ipAndLocationPojos = null;
try {
ipAndLocationPojos = DataProcessManager.getPojoList(
StaticValue.ipLibrartPath, StaticValue.encoding);
} catch (IOException e) {
e.printStackTrace();
}
// 转换为数组
ipLocationPojoArr = DataProcessManager
.convertListToArrayAndSort(ipAndLocationPojos);
try {
SerDeUtil.saveObject(ipLocationPojoArr,
StaticValue.serde_obj_filepath,
StaticValue.cacheByteArrayLength);
} catch (IOException e) {
e.printStackTrace();
}
}
- 优化进阶
- IO优化
直接优化 : 提高IO效率
间接优化 : 数据大小也会应该效率问题
文件大小变动
首次2500 非首次 520-600