本文微信公众号「AndroidTraveler」首发.
背景
时值毕业季, 很多毕业生初入职场.
因此, 这边也写了一些新手相关的 Android 技术点.
比如上一篇的 Android 开发你需要了解的那些事 https://mp.weixin.qq.com/s/P6UlSBkhnyriow-pT-X9Gg 就是列举了一些小点, 避免新手 Android 开发者踩坑.
同时, 也是恰逢暑假, 因此大学生处于放假阶段.
这一篇主要是来自一位大学生的提问.
因此这边分享一下我个人的解题思路和方法, 希望能够对他有所启发.
欢迎大家交流分享.
题目
使用语言: JAVA
需求: 读取一个 Excel 表格里面的数据 (例如: 姓名 + 分数), 对其进行重新排序 (按分数高低), 然后输出在另一个 Excel 表格.
分析
一般对需求我们都采取拆分思维.
将大问题拆成小问题, 小问题解决了, 整个大问题也就解决了.
这个需求很明确, 需要解决三个问题:
读取 Excel 表格数据
对数据排序
将数据写入另一个 Excel 表格
我们这里要求使用 Java 语言, 而 Java 语言一个很重要的点就是面向对象.
因此首先我们要考虑一下, 这个题目里面有哪些类需要我们创建.
大概可以想象需要下面这些类:
读取数据类: ExcelReader
写入数据类: ExcelWriter
数据排序类: 由于 Java API 自带, 所以不需要重复造轮子
数据模型类: StudentScore
启动类: ParserStart, 带有 main 方法
大概的 UML 图如下:
此时我们可以写出 v0.1 代码:
- ExcelReader.java:
- import java.util.List;
- public class ExcelReader {
- public List<StudentScore> read(String fileName) {
- //TODO
- return null;
- }
- }
- ExcelWriter.java:
- import java.util.List;
- public class ExcelWriter {
- public void write(String fileName, List<StudentScore> list) {
- //TODO
- }
- }
- StudentScore.java:
- public class StudentScore {
- private String name;
- private int score;
- public StudentScore(String name, int score) {
- super();
- this.name = name;
- this.score = score;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getScore() {
- return score;
- }
- public void setScore(int score) {
- this.score = score;
- }
- }
- ParserStart.java:
- import java.util.List;
- public class ParserStart {
- public static void main(String[] args) {
- // 第一步: 读取数据
- List<StudentScore> dataList = new ExcelReader().read("input.xls");
- // 第二步: 排序
- //TODO
- // 第三部: 写入数据
- new ExcelWriter().write("output.xls", dataList);
- }
- }
好了, 基本框架搭好了. 接下来就一步一步来实现我们的方法.
v0.2 代码: 完善 ExcelReader 的 read 方法
Excel 的读取方法有第三方的库可以使用, 因此我们不需要自己写.
我们这里使用的是第三方的 Apache 提供的 POI 库.
下载链接地址: https://poi.apache.org/download.html
写这篇文章时使用到的版本是 4.1.0
解压然后将 jar 包引入 Eclipse 项目即可.
接下来就是实际编写代码了, 详情见注释.
我们要读取的文件示例如下:
- ExcelReader.java:
- import java.io.File;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.poi.EncryptedDocumentException;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.ss.usermodel.WorkbookFactory;
- public class ExcelReader {
- public List<StudentScore> read(String fileName) throws EncryptedDocumentException, IOException {
- if (fileName == null) return null;
- File xlsFile = new File(fileName);
- if (!xlsFile.exists()) return null;
- // 工作表
- Workbook workbook = WorkbookFactory.create(xlsFile);
- // 表个数
- int numberOfSheets = workbook.getNumberOfSheets();
- // System.out.println(numberOfSheets);
- if (numberOfSheets <= 0) return null;
- List<StudentScore> list = new ArrayList<>();
- // 我们的需求只需要处理一个表, 因此不需要遍历
- Sheet sheet = workbook.getSheetAt(0);
- // 行数
- int rowNumbers = sheet.getLastRowNum() + 1;
- // System.out.println(rowNumbers);
- StudentScore score;
- // 读数据, 第二行开始读取
- for (int row = 1; row <rowNumbers; row++) {
- Row r = sheet.getRow(row);
- // System.out.println(r.getPhysicalNumberOfCells());
- // 我们只需要前两列
- if (r.getPhysicalNumberOfCells()>= 2) {
- score = new StudentScore(r.getCell(0).toString(), (int) Double.parseDouble(r.getCell(1).toString()));
- list.add(score);
- }
- }
- return list;
- }
- }
v0.3 代码: 对读取后的数据做排序处理
在 v0.2 版本中, 我们成功读取了数据, 但是我们读取的数据是按照 Excel 里面的顺序的, 因此我们需要做排序处理. Java 函数库有对集合进行排序的方法. 不过我们需要对 Model 进行额外处理, 添加排序规则. 因为排序可以是从小到大排, 也可以是从大到小排.
- StudentScore.java:
- public class StudentScore implements Comparable<StudentScore>{
- private String name;
- private int score;
- public StudentScore(String name, int score) {
- super();
- this.name = name;
- this.score = score;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getScore() {
- return score;
- }
- public void setScore(int score) {
- this.score = score;
- }
- @Override
- public String toString() {
- return "StudentScore [name=" + name + ", score=" + score + "]";
- }
- @Override
- public int compareTo(StudentScore o) {
- return o.score - this.score;
- }
- }
- ParserStart.java:
- import java.util.Collections;
- import java.util.List;
- public class ParserStart {
- public static void main(String[] args) throws Exception{
- // 第一步: 读取数据
- List<StudentScore> dataList = new ExcelReader().read("resource/input.xls");
- System.out.println(dataList);
- // 第二步: 排序
- Collections.sort(dataList);
- System.out.println(dataList);
- // 第三部: 写入数据
- // new ExcelWriter().write("output.xls", dataList);
- }
- }
v0.4 代码: 将排序后的数据写入另一个 Excel 表中
在 v0.3 版本中, 我们完成了数据的排序, 接下来我们需要将排好序的数据写到 output.xls 中.
ExcelWriter.java
- import java.io.File;
- import java.io.IOException;
- import java.util.List;
- import org.apache.poi.hssf.usermodel.HSSFRow;
- import org.apache.poi.hssf.usermodel.HSSFSheet;
- import org.apache.poi.hssf.usermodel.HSSFWorkbook;
- public class ExcelWriter {
- public void write(String fileName, List<StudentScore> list) {
- HSSFWorkbook workbook = new HSSFWorkbook();
- HSSFSheet sheet = workbook.createSheet("StudentScore");
- // 创建 Excel 标题行, 第一行
- HSSFRow headRow = sheet.createRow(0);
- headRow.createCell(0).setCellValue("姓名");
- headRow.createCell(1).setCellValue("分数");
- // 往 Excel 表中遍历写入数据
- for (StudentScore studentScore : list) {
- createCell(studentScore, sheet);
- }
- File xlsFile = new File(fileName);
- try {
- // 或者以流的形式写入文件 workbook.write(new FileOutputStream(xlsFile));
- workbook.write(xlsFile);
- } catch (IOException e) {
- // TODO
- } finally {
- try {
- workbook.close();
- } catch (IOException e) {
- // TODO
- }
- }
- }
- // 创建 Excel 的一行数据.
- private void createCell(StudentScore studentScore, HSSFSheet sheet) {
- HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1);
- dataRow.createCell(0).setCellValue(studentScore.getName());
- dataRow.createCell(1).setCellValue(studentScore.getScore());
- }
- }
ParserStart.java
- import java.util.Collections;
- import java.util.List;
- public class ParserStart {
- public static void main(String[] args) throws Exception {
- // 第一步: 读取数据
- List<StudentScore> dataList = new ExcelReader().read("resource/input.xls");
- System.out.println(dataList);
- // 第二步: 排序
- Collections.sort(dataList);
- System.out.println(dataList);
- // 第三部: 写入数据
- new ExcelWriter().write("resource/output.xls", dataList);
- }
- }
到此, 通过几个版本的迭代, 我们的需求就实现了.
NOTE:
在本项目中, input.xls 放在 resource 文件夹下面. 所以最终版本传入的路径是 resource/input.xls. 另外输出的时候这边发现 Eclipse 没有显示出来 output.xls, 需要刷新一下.
此外, 下载我的项目运行验证时, 可能需要修改下 JRE.
另外 jar 包不要引入错位置了:
当然, 还有几个待完善的点需要说明下:
这里没有对输入表的数据做合法性校验, 比如分数为负数的情况是否需要做一些提示之类的操作.
这里判断文件不存在时, 直接返回 null. 而且没有判断文件是否为 Excel 文件. 这里就交由大家完善. 而且这边异常没有做处理, 直接 throws.
这里因为简单就没有做抽象. 但是考虑可能需要读写 Word 或者 PDF 或者其他文件, 所以可以考虑引入继承和多态. 抽取基类.
合理组织文件夹和命名.
另外说一下有什么应用场景吧, 其实还真有.
移动端有多语言, 想象一下产品给你一张带有多语言的 Excel 表.
如果你一个一个拷贝到多个语言的资源文件下, 这效率难以想象.
而如果你用了这一节的内容, 分分钟读取 Excel 按照你要的规则组装后输出到控制台.
想想就有点 6 啊.
好了, 本期内容到此结束, 欢迎留言交流讨论.
如果你有想了解的知识点, 欢迎公众号留言私信, 也许下一个 pick 的就是你.
源码获取地址:
https://github.com/nesger/JavaSamples/tree/master/ParseExcel
参考链接:
Java 读取 Excel 数据: 基于 Apache POI(一)
Java 读取和解析 Excel 数据: 基于 Apache POI(二)
Java 导出数据行写入到 Excel 表格: 基于 Apache POI
来源: https://www.cnblogs.com/nesger/p/11234148.html