zoukankan      html  css  js  c++  java
  • Java 读写 excel 实战完全解析

    背景

    时值毕业季,很多毕业生初入职场。

    因此,这边也写了一些新手相关的 Android 技术点。

    比如上一篇的 Android 开发你需要了解的那些事 就是列举了一些小点,避免新手 Android 开发者踩坑。

    同时,也是恰逢暑假,因此大学生处于放假阶段。

    这一篇主要是来自一位大学生的提问。

    因此这边分享一下我个人的解题思路和方法,希望能够对他有所启发。

    欢迎大家交流分享。

    题目

    使用语言:JAVA

    需求:读取一个Excel表格里面的数据(例如:姓名+分数),对其进行重新排序(按分数高低),然后输出在另一个Excel表格。

    分析

    一般对需求我们都采取拆分思维。
    将大问题拆成小问题,小问题解决了,整个大问题也就解决了。

    这个需求很明确,需要解决三个问题: 1. 读取 Excel 表格数据 2. 对数据排序 3. 将数据写入另一个 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 库。
    下载链接地址:
    写这篇文章时使用到的版本是 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 包不要引入错位置了:

     

    当然,还有几个待完善的点需要说明下: 1. 这里没有对输入表的数据做合法性校验,比如分数为负数的情况是否需要做一些提示之类的操作。 2. 这里判断文件不存在时,直接返回 null。而且没有判断文件是否为 excel 文件。这里就交由大家完善。而且这边异常没有做处理,直接 throws。 3. 这里因为简单就没有做抽象。但是考虑可能需要读写 word 或者 pdf 或者其他文件,所以可以考虑引入继承和多态。抽取基类。 4. 合理组织文件夹和命名。

    另外说一下有什么应用场景吧,其实还真有。

    移动端有多语言,想象一下产品给你一张带有多语言的 excel 表。
    如果你一个一个拷贝到多个语言的资源文件下,这效率难以想象。
    而如果你用了这一节的内容,分分钟读取 excel 按照你要的规则组装后输出到控制台。
    想想就有点 6 啊。

    好了,本期内容到此结束,欢迎留言交流讨论。

    如果你有想了解的知识点,欢迎公众号留言私信,也许下一个 pick 的就是你。

    源码获取地址:

    参考链接:
    Java读取Excel数据:基于Apache POI(一)
    Java读取和解析Excel数据:基于Apache POI(二)
    Java导出数据行写入到Excel表格:基于Apache POI

    from: https://zhuanlan.zhihu.com/p/74922498

  • 相关阅读:
    计算几何——交点、面积的计算
    计算几何——认识基本object:点、线、面 。
    图的拓扑排序——卡恩算法
    Manacher
    如何不改造 HBase 就能应对复杂查询场景
    如何做沟通
    大数据磁盘阵列技术
    Android系统架构开篇
    Apache Kylin 原理介绍与新架构分享(Kylin On Parquet)
    遭遇突然提问慌了?掌握关键2点完美应对zz
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/14540752.html
Copyright © 2011-2022 走看看