这个框框我去不掉,只能留在这!!!
一、为啥要比较excel表格中某一列的数据
最近有产品小姐姐来找我帮忙(我所负责的项目中的数据需要对比下),就是她那边有两张数据库中导出来的excel表格,需要比较两张表中的某一列值是否是不相等的,如果有不相等的需要我再提供给他不相等的唯一标识的编码(最好还是一张excel表格),这不是难为我嘛!唉,谁让我乐于助人呢,哈哈
二、使用步骤
1.引入依赖
因为需要比较两个集合中的元素,我这一引用了guava的一个封装好的方法,所以需要引入依赖(有不想引入依赖的猴宝宝们我下面也会给大家提供两个我自己写的方法,亲测有效哦)
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>29.0-jre</version> </dependency>
2.读入数据
读取excel中数据的代码如下,具体的读取解释都在代码中给大家注释了,实属保姆级教程:
public static void main(String[] args) throws IOException {
//将文件中数据初始化集合
List<String> areaCodes1 = new ArrayList<>();
List<String> areaCodes2 = new ArrayList<>();
//以csv格式读取此电脑上的数据(csv文件读取速度较快,相当于文本格式,且数据不会出现差错)
//这里读取的是文件中所有的数据
List<String> areaCodeList1 = FileUtils.readLines(new File("C:\\Users\\Administrator\\Desktop\\机构所在省,市,县.csv"), "UTF-8");
List<String> areaCodeList2 = FileUtils.readLines(new File("C:\\Users\\Administrator\\Desktop\\t_abs_basic_area.csv"), "UTF-8");
//获取文件1中某一列中的所有数据添加到集合中
//skip(1)为跳过表头
areaCodeList1.stream().skip(1).forEach(s -> {
//因为csv文件中在读取的时候是以逗号进行隔开的,所以这里将所有数据以逗号进行分割,这样就可以获取每一列的数据
String[] ss = s.split(",");
//这里获取到文件中需要比较的那一列数据
areaCodes1.add(ss[6]);
});
//获取文件2中某一列中的所有数据添加到集合中
//skip(1)为跳过表头
areaCodeList2.stream().skip(1).forEach(s -> {
//因为csv文件中在读取的时候是以逗号进行隔开的,所以这里将所有数据以逗号进行分割,这样就可以获取每一列的数据
String[] ss = s.split(",");
//这里获取到文件中需要比较的那一列数据
areaCodes2.add(ss[1]);
});
//用来作比较的set初始化集合
Set<String> areaCodesSet1 = Sets.newHashSet(areaCodes1);
Set<String> areaCodesSet2 = Sets.newHashSet(areaCodes2);
//使用guava封装好的对比方法进行对比,返回的也是set1中有的数据,而set2没有的
//目前用过比较好的比较方法,性能也不错,底层源码用的是迭代器来实现的,感兴趣的猴宝宝可以看下
//机构所在省,市,县表中存在,但area_code表中不存在的code编码set集合
Sets.SetView<String> difference1 = Sets.difference(areaCodesSet1, areaCodesSet2);
//area_code表中存在,但机构所在省,市,县表中不存在的code编码set集合
Sets.SetView<String> difference2 = Sets.difference(areaCodesSet2, areaCodesSet1);
//输出到控制台,方便查看结果
System.out.println("机构所在省,市,县表中存在,但area_code表中不存在的code编码: " + difference1);
System.out.println("area_code表中存在,但机构所在省,市,县表中不存在的code编码: " + difference2);
System.out.println("机构所在省,市,县表中存在,但area_code表中不存在的code编码数量: " + difference1.size());
System.out.println("area_code表中存在,但机构所在省,市,县表中不存在的code编码数量: " + difference2.size());
//将对比后的数据写到指定的文件中,自己封装的方法,下面会给出来这段代码哦
exportToExcel(difference1, difference2);
}
这里读取的时候有个小技巧,就是可以将excel文件另存为csv格式的文件 ,这种格式相当于文本文件,并且也不会做一些数据上的转换,读取的速度也是很快的,转换完之后尽量用notepad++转成UTF-8格式的编码,这样读取中文的话不会出现乱码。
另存为csv文件:
直接右键点击csv文件,然后使用notepad++打开,转换为UTF-8编码
3.写入数据
写入的逻辑比较复杂,因为同时将两个集合写入到两列确实是比较麻烦的(不想这么麻烦的话我下面会介绍一种比较简单写入到文本文件的方法,两行代码就可以解决),所以我在代码里也给大家做了详细的解释,博主没有写明白的欢迎来私信哦,代码如下:
/**
* 创建excel文件并插入数据
* @param set1
* @param set2
*/
public static void exportToExcel(Set<String> set1, Set<String> set2) {
//数据存放到excel中集合初始化
List<String> list1 = new ArrayList<>(set1);
List<String> list2 = new ArrayList<>(set2);
//1.创建Excel工作簿
//这里并没有设置格式什么的,感兴趣的猴宝宝可以自行再研究下哦
HSSFWorkbook workbook = new HSSFWorkbook();
//2.创建一个工作表
HSSFSheet sheet = workbook.createSheet("sheet2");
//3.创建第一行
HSSFRow row = sheet.createRow(0);
HSSFCell cell = null;
//4.插入第一行表头数据
for (int i = 0; i < title.length; i++) {
cell = row.createCell(i);
cell.setCellValue(title[i]);
}
//这里需要搞个计数器,写入好一行之后需要自动写到下一行
int i = 1;
//5.追加数据
//判断两个集合差集数据的大小,放入到第一列还是第二列
if (list1.size() >= list2.size()) {
for (String m : list1) {
//需要写入第几行
HSSFRow row2 = sheet.createRow(i);
//在第一列中追加的数据
HSSFCell cell2 = row2.createCell(0);
cell2.setCellValue(m);
//在第二列中追加的数据
cell2 = row2.createCell(1);
if (i <= list2.size()) {
cell2.setCellValue(list2.get(i - 1));
}
i++;
}
} else {
for (String m : list2) {
//需要写入第几行
HSSFRow row2 = sheet.createRow(i);
//在第二列中追加的数据
HSSFCell cell2 = row2.createCell(1);
cell2.setCellValue(m);
//在第一列中追加的数据
cell2 = row2.createCell(0);
if (i <= list1.size()) {
cell2.setCellValue(list1.get(i - 1));
}
i++;
}
}
//创建一个文件,将Excel内容存盘
File file = new File(newFilePath);
try {
//创建新文件
file.createNewFile();
//输出到电脑指定的文件路径中
FileOutputStream stream = FileUtils.openOutputStream(file);
workbook.write(stream);
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
三、最后实现的效果
两张源文件中的数据:
控制台展现的结果:
写入后的excel文件中的数据:
表头和比较后的数据都会正常写入
上面比较两个集合的方法其实有很多,又不想引入依赖的小伙伴我这里再给大家提供两种,也是亲测有效哦
//自己封装的比较方法,返回的是第一个集合中存在但是第二个集合中不存在的数据
public static List<String> subList(List<String> list1, List<String> list2) {
list1.removeAll(list2);
return list1;
}
//看的是某个博主的方法,步骤有点多,但是也可以实现返回list1中有的数据,而list2没有的
public static List<String> getDelOrAdd(List<String> list1, List<String> list2) {
//方法主要用于返回list1中有的数据,而list2没有的
//当list1和list2数据相同时返回空的list
//空间换时间 降低时间复杂度
Map<String, String> tempMap = new HashMap<>();
for (String str : list2) {
tempMap.put(str, str);
}
//LinkedList 频繁添加删除 也可以ArrayList容量初始化为List1.size(),防止数据量过大时频繁扩容以及数组复制
List<String> resList = new LinkedList<>();
for (String str : list1) {
if (!tempMap.containsKey(str)) {
resList.add(str);
}
}
return resList;
}
上面写入到文件里的这段代码比较复杂,还有一种非常简单的方法,就像喝水一样简单,只用两行代码,老规矩,解释还是放到代码中
//比较简单的一种写入到电脑中的方法,不在乎格式想要直接写入到txt文件中,就可以用这种方法
public static void writeExcel(Set<String> set1, Set<String> set2) throws IOException {
//把集合里面的内容写入文件,以指定字符串结束写入
//void writeLines(File file,Collection<?> lines,String lineEnding,boolean append)
List<String> list1 = new ArrayList<>(set1);
List<String> list2 = new ArrayList<>(set2);
//直接写入到文本文件中,一种非常简单的方法,但是这种方法需要大家自己手动先把文件创建好哈,相比较上面那种写入到excel中的方法,手动创建简直就是1+1那么简单
FileUtils.writeLines(new File("C:\\Users\\Administrator\\Desktop\\机构所在省,市,县表中存在,但area_code表中不存在的code编码.txt"), "GBK", list1, ",", true);
FileUtils.writeLines(new File("C:\\Users\\Administrator\\Desktop\\area_code表中存在,但机构所在省,市,县表中不存在的code编码.txt"), "GBK", list2, ",", true);
}
总结
只要你想,什么都可以用代码来解决(除了大变活人,让我用代码给他找对象的叉出去),这段代码也是浪费了好几个小时,但是以后在有这种需要比较的就可以直接拿来复用了,所以还是很有意义的,当然,读取完数据也可以用来生成sql脚本等等比较省力的操作,有兴趣的同学可以找我私聊哦