JAVA读写Excel(jxl,poi,easyExcel)

news2024/9/23 1:33:49

目录

一、需求描述

二、具体操作Excel的常用方法

方法一: 使用jxl

方法二: POI

方法三:EasyExcel

三、总结


一、需求描述

前端有时候会传送 Excel 文件给后端(Java)去解析,那我们作为后端该如何实现对 Excel 文件的解析和数据读取呢?

使用Java对Excel文件进行读写,文件后缀可能为.xls, .xlsx

二、具体操作Excel的常用方法

方法一: 使用jxl

JXL:  开源库,支持.xls文件(EXCEL 2003格式)的读写

注意: JXL不支持.xlsx文件(EXCEL 2007格式)的读写

使用:

1. pom.xml文件引入 
 <!--读取excel文件-->
        <!-- https://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl -->
        <dependency>
            <groupId>net.sourceforge.jexcelapi</groupId>
            <artifactId>jxl</artifactId>
            <version>2.6.12</version>
        </dependency>


2. jxl读文件

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;


//读文件

/**
     * 返回上传的Excel表格的内容
     * Jxl是一款常用的Java中操作Excel的API,但其只对xls有效,对2007版本以上的Excel(xlsx)很难处理。
     */
    public static List<String[]> parseExcel(String filePath) throws Exception {
        List<String[]> list = new ArrayList<>();
        Workbook wb = Workbook.getWorkbook(new File(filePath));
        Sheet sheet = wb.getSheets()[0];
        int columns = sheet.getRow(0).length;
        for (int i = 0; i < sheet.getRows(); i++) {
            String[] line = new String[columns];
            for (int j = 0; j < columns; j++) {
                Cell cell = sheet.getCell(j, i);
                String content = null;
                if (cell != null) {
                    content = cell.getContents();
                }
                if (content != null && content.trim().length() == 0) {
                    content = "";
                }
                line[j] = content;
            }
            list.add(line);
        }
        return list;
    }


// 写文件

public static void write2File(String filePath, List<GradeVo> gradeVoList) throws IOException, WriteException {
        // 写入文件

        File file = new File(filePath);
        // 创建工作簿
        WritableWorkbook workbook = Workbook.createWorkbook(file);
        // 创建工作表
        WritableSheet sheet = workbook.createSheet("Sheet1", 0);
        AtomicInteger rowIndex = new AtomicInteger(1);
        try {
            //写表头
            Label label0 = new Label(0, 0, "学号");
            sheet.addCell(label0);
            label0 = new Label(1, 0, "姓名");
            sheet.addCell(label0);
            label0 = new Label(2, 0, "班级");
            sheet.addCell(label0);
            label0 = new Label(3, 0, "每次作业分");
            sheet.addCell(label0);
            label0 = new Label(4, 0, "作业平均分");
            sheet.addCell(label0);
            label0 = new Label(5, 0, "考勤次数");
            sheet.addCell(label0);
            label0 = new Label(6, 0, "回答问题次数");
            sheet.addCell(label0);
            label0 = new Label(7, 0, "期末分数");
            sheet.addCell(label0);
            label0 = new Label(8, 0, "最终分");
            sheet.addCell(label0);

            // 创建单元格并写入数据
            for (GradeVo value : gradeVoList) {
                Label label = new Label(0, rowIndex.get(), value.getSNo());
                sheet.addCell(label);
                label = new Label(1, rowIndex.get(), value.getSName());
                sheet.addCell(label);
                label = new Label(2, rowIndex.get(), value.getSClass());
                sheet.addCell(label);
                label = new Label(3, rowIndex.get(), JSON.toJSONString(value.getGrade()));
                sheet.addCell(label);
                label = new Label(4, rowIndex.get(), value.getAvgScore() + "");
                sheet.addCell(label);
                label = new Label(5, rowIndex.get(), value.getSignInTimes() + "");
                sheet.addCell(label);
                label = new Label(6, rowIndex.get(), value.getAnswerTimes() + "");
                sheet.addCell(label);
                label = new Label(7, rowIndex.get(), value.getFinalScore() + "");
                sheet.addCell(label);
                label = new Label(8, rowIndex.get(), value.getTotalScore() + "");
                sheet.addCell(label);
                rowIndex.addAndGet(1);
            }

            // 写入数据
            workbook.write();
            // 关闭工作簿
            workbook.close();

        }catch (WriteException e) {
            throw new RuntimeException(e);
        }
    }

更多用法:

//单元格合并
sheet.mergeCells(0,2,0,3); //把第 0 列第 2 行的单元格和第 0 列第 3 行的单元格合并

//设置单元格列宽和行高
sheet.setColumnView(0,10);//设置第 0 列的宽为10
sheet.setRowView(0,1000);//设置第 0 行的高为10

//插入字符串数据可用String[]数组(注意需要在下面遍历数组!)
String[] str = {"1","2"};


//设置单元格内容样式                           设置字体              字体大小   是否加粗
WritableFont font=new WritableFont(WritableFont.createFont("宋体"),12,WritableFont.BOLD);
WritableCellFormat format = new WritableCellFormat(font);
//水平居中
format.setAlignment(jxl.format.Alignment.CENTRE);

方法二: POI

POI (Poor Obfuscation Implementation)主要是指 Apache提供的操作Office的基础工具包(Apache POI),Apache POI 是一个底层的工具类,可实现的功能最全。

缺点:

解析文件时一次性全部加载到内存中,系统并发量不大时可行,一旦并发上来后会产生OOM或者JVM频繁的full gc

操作:

pom文件引入:

引入 Apache POI 和 Apache POI-OOXML 这两个类库,Maven坐标如下:

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.0.1</version>
    </dependency>
注意:使用HSSF操作.xls格式文件,使用XSSF操作.xlsx文件 

读文件:

private final static String xls = "xls";
    private final static String xlsx = "xlsx";

    /**
     * 读入excel文件,解析后返回
     * @param file
     * @throws IOException
     */
    public static List<String[]> readExcel(MultipartFile file) throws IOException {
        //检查文件
        checkFile(file);
        //获得Workbook工作薄对象
        Workbook workbook = getWorkBook(file);
        //创建返回对象,把每行中的值作为一个数组,所有行作为一个集合返回
        List<String[]> list = new ArrayList<String[]>();
        if(workbook != null){
            for(int sheetNum = 0;sheetNum < workbook.getNumberOfSheets();sheetNum++){
                //获得当前sheet工作表
                Sheet sheet = workbook.getSheetAt(sheetNum);
                if(sheet == null){
                    continue;
                }
                //获得当前sheet的开始行
                int firstRowNum  = sheet.getFirstRowNum();
                //获得当前sheet的结束行
                int lastRowNum = sheet.getLastRowNum();
                //循环除了第一行的所有行
                for(int rowNum = firstRowNum+1;rowNum <= lastRowNum;rowNum++){ //为了过滤到第一行因为我的第一行是数据库的列
                    //获得当前行
                    Row row = sheet.getRow(rowNum);
                    if(row == null){
                        continue;
                    }
                    //获得当前行的开始列
                    int firstCellNum = row.getFirstCellNum();
                    //获得当前行的列数
                    int lastCellNum = row.getLastCellNum();//为空列获取
//                    int lastCellNum = row.getPhysicalNumberOfCells();//为空列不获取
//                    String[] cells = new String[row.getPhysicalNumberOfCells()];
                    String[] cells = new String[row.getLastCellNum()];
                    //循环当前行
                    for(int cellNum = firstCellNum; cellNum < lastCellNum;cellNum++){
                        Cell cell = row.getCell(cellNum);
                        cells[cellNum] = getCellValue(cell);
                    }
                    list.add(cells);
                }
            }
        }
        logger.info(gson.toJson(list));
        return list;
    }
    public static void checkFile(MultipartFile file) throws IOException{
        //判断文件是否存在
        if(null == file){
            throw new FileNotFoundException("文件不存在!");
        }
        //获得文件名
        String fileName = file.getOriginalFilename();
        //判断文件是否是excel文件
        if(!fileName.endsWith(xls) && !fileName.endsWith(xlsx)){
            throw new IOException(fileName + "不是excel文件");
        }
    }
    public static Workbook getWorkBook(MultipartFile file) {
        //获得文件名
        String fileName = file.getOriginalFilename();
        //创建Workbook工作薄对象,表示整个excel
        Workbook workbook = null;
        try {
            //获取excel文件的io流
            InputStream is = file.getInputStream();
            //根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象
            if(fileName.endsWith(xls)){
                //2003
                workbook = new HSSFWorkbook(is);
            }else if(fileName.endsWith(xlsx)){
                //2007
                workbook = new XSSFWorkbook(is);
            }
        } catch (IOException e) {
            logger.info(e.getMessage());
        }
        return workbook;
    }
    public static String getCellValue(Cell cell){
        String cellValue = "";
        if(cell == null){
            return cellValue;
        }
        //把数字当成String来读,避免出现1读成1.0的情况
        if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
            cell.setCellType(Cell.CELL_TYPE_STRING);
        }
        //判断数据的类型
        switch (cell.getCellType()){
            case Cell.CELL_TYPE_NUMERIC: //数字
                cellValue = String.valueOf(cell.getNumericCellValue());
                break;
            case Cell.CELL_TYPE_STRING: //字符串
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            case Cell.CELL_TYPE_BOOLEAN: //Boolean
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case Cell.CELL_TYPE_FORMULA: //公式
//                cellValue = String.valueOf(cell.getCellFormula());
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            case Cell.CELL_TYPE_BLANK: //空值
                cellValue = "";
                break;
            case Cell.CELL_TYPE_ERROR: //故障
                cellValue = "非法字符";
                break;
            default:
                cellValue = "未知类型";
                break;
        }
        return cellValue;
    }

官网文档:

Busy Developers' Guide to HSSF and XSSF Features

  • 工作簿对象支持设置一些全局性质的对象,例如:
  1.  单元格样式的对象。一个工作簿最多支持6w个单元格的样式;
  2.  创建字体样式的对象。一个工作簿最多支持32767个 字体样式;
  • 工作表对象支持只在单个工作表生效的设置,例如:
  1. 设置筛选按钮; 
  2. 设置某列的自适应列宽;
  3. 冻结窗格;
  4. 拆分窗口;
  • 行对象

Row 支持的操作有:

  1. 创建单元格
  2. 获取/遍历单元格
  3. 设置行高
  4. 获取行号
  5. 设置/隐藏行
  • 单元格对象

单元格对象支持对单个单元格进行设置,例如:

  1. 获取/设置单元格的值
  2. 获取/设置单元格的类型(字符串、数值[数字/日期]、布尔值、公式、错误值、空)
  3. 获取/设置单元格的样式
  4. 获取/设置超链接
  • 单元格的值

    单元格的值有7种类型[CellType](数值、字符串、公式、空值、布尔值、错误值)

方法三:EasyExcel

优点:

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
        easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便

操作:

pom文件:

读Excel:DEMO代码地址:https://github.com/alibaba/easyexcel/blob/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java
/**
     * 最简单的读
     * <p>1. 创建excel对应的实体对象 参照{@link DemoData}
     * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
     * <p>3. 直接读即可
     */
    @Test
    public void simpleRead() {
        String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
    }



写Excel:DEMO代码地址:https://github.com/alibaba/easyexcel/blob/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java
/**
     * 最简单的写
     * <p>1. 创建excel对应的实体对象 参照{@link com.alibaba.easyexcel.test.demo.write.DemoData}
     * <p>2. 直接写即可
     */
    @Test
    public void simpleWrite() {
        String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";
        // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
    }

官网文档:

https://easyexcel.opensource.alibaba.com/docs/current/EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目,在尽可能节约内存的情况下支持读写百M的Excel。icon-default.png?t=N7T8https://easyexcel.opensource.alibaba.com/docs/current/读Excel | Easy Excel 官网

三、总结

  • 如果操作Excel复杂度高(.xls,.xlsx都存在,且内容格式复杂),建议使用POI。
  • 如果操作Excel数据量大并且对对性能有要求,可以使用EasyExcel。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2102585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux内核源码-USB驱动分析

基础层次详解 通用串行总线&#xff08;USB&#xff09;主要用于连接主机和外部设备&#xff08;协调主机和设备之间的通讯&#xff09;&#xff0c;USB 设备不能主动向主机发送数据。USB 总线采用拓扑&#xff08;树形&#xff09;&#xff0c;主机侧和设备侧的 USB 控制器&a…

《亿级流量系统架构设计与实战》第十二章 评论服务

评论服务 一、概述二、单级评论模式1、模型设计2、分库分表必要性3、高并发问题 三、二级评论模式1、模型设计2、评论审核与状态3、按照热度排序4、评论读取流程图5、架构总览 四、盖楼评论模式1、数据库递归查询2、数据库保存完整楼层3、图数据库 内容总结自《亿级流量系统架构…

关于IDEA的快捷键不能使用的原因

有时候IDEA的快捷键用不了&#xff0c;这时应该是快捷键发生冲突了&#xff0c;重新设置一下即可。以批量修改变量名称的shift f6为例&#xff08;我的这个快捷键用不了&#xff09;&#xff1a; 初始的rename的快捷键为shift f6 这个快捷键是冲突的&#xff0c;所以我们需要…

探索PDF的奥秘:pdfrw库的神奇之旅

文章目录 探索PDF的奥秘&#xff1a;pdfrw库的神奇之旅背景&#xff1a;为何选择pdfrw&#xff1f;pdfrw是什么&#xff1f;如何安装pdfrw&#xff1f;五个简单的库函数使用方法场景应用&#xff1a;pdfrw在实际工作中的应用常见问题与解决方案总结 探索PDF的奥秘&#xff1a;p…

安防监控视频平台LntonAIServer视频智能分析平台新增视频质量诊断功能

随着安防行业的快速发展&#xff0c;视频监控系统已经成为维护公共安全和个人隐私的重要工具。然而&#xff0c;由于各种因素的影响&#xff0c;视频流的质量可能会受到影响&#xff0c;从而导致监控效果不佳。为了解决这一问题&#xff0c;LntonAIServer推出了全新的视频质量诊…

基于.NET6的WPF基础总结(下)

目录 一、集合控件 1. ListBox可选项列表 2. ListView数据列表控件 3. DataGrid数据表格控件 4. ComboBox下拉框控件 5. TabControl 6. TreeView 树形控件 7. Menu菜单 8. ContextMenu上下文菜单 二、图像控件 1. Ellipse 椭圆 2. Line线段 3. Rectangle矩形 4.…

如何打造中小学在线教学平台?Java SpringBoot集成Vue,教育资源管理新篇章

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

基于Transformer架构训练LLM大语言模型:Transformer架构工作原理

视频讲解&#xff1a;Transformer架构的工作原理讲解_哔哩哔哩_bilibili 一 Transformer架构总体架构 1 总体架构图 总体架构说明&#xff1a; 输入层 词嵌入&#xff08;Word Embeddings&#xff09;: 输入文本中的每个词都被映射到一个高维空间中的向量&#xff0c;这些向…

HTML静态网页成品作业(HTML+CSS)——动漫大耳朵图图网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

智能化的知识管理:大模型在知识图谱构建中的突破性应用

转自&#xff1a;大模型奇点说 知识图谱是一种以图形结构组织数据的知识表示形式&#xff0c;其中&#xff0c;概念、事件、实体等知识单元通过节点呈现&#xff0c;而它们之间的各种关系则通过边来描述。知识图谱的显著特点在于&#xff0c;通过关系的定义&#xff0c;为节点提…

EmguCV学习笔记 VB.Net 9.3 移动检测类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

第十一课,多分支判断

一&#xff0c;多分支结构 某些场景下&#xff0c;判断条件不止一个&#xff0c;可能有多个。 语法格式&#xff08;下图左&#xff09;&#xff1a; *需要注意&#xff1a;这里仅是以5种选择作为例子&#xff0c; 可以根据自己的需要&#xff0c;在if...else的中间插入任意…

OrangePi AIpro 香橙派 昇腾 Ascend C 算子开发 与 调用 - Tiling实现

OrangePi AIpro 香橙派 昇腾 Ascend C 算子开发 与 调用 - Tiling实现 flyfish 前置知识 基于Kernel直调工程的算子开发流程图 其中有一个Tiling实现 什么是Tiling、Tiling实现 计算API&#xff0c;包括标量计算API、向量计算API、矩阵计算API&#xff0c;分别实现调用S…

51单片机-串口通信(电脑向串口助手发送数据不接收)

80C52中的串口通过SCON寄存器配置波特率位可变的&#xff0c;因此&#xff0c;需要通过计算定时器1的参与&#xff0c;在定时器配置过程中选择定时器的相关寄存器TMOD来配置定时器的模式为模式2&#xff08;8位自动重装定时器&#xff0c;如上图&#xff0c;TL1为计数器&#x…

SpringBoot动态配置Nacos

重要知识点 Nacos属性的简单使用 将SpringBoot中的所有配置全部放入到Nacos中 开发人创建单独的命名空间,修改互不影响 Nacos经常变动的配置抽离到外部文件中 将项目中的所有配置全部放到到 1. 首先引入包 <!-- nacos 接入--><!-- https://mvnrepository.com/artifact…

网络安全服务基础Windows--第14节-数字签名

散列函数&#xff08;Hash Function&#xff09;&#xff0c;也称为哈希函数&#xff0c;是密码学中⼀个重要的⼯具。它能够将任意⻓度的输⼊数据转换为固定⻓度的输出&#xff08;散列值或哈希值&#xff09;。这种转换过程具有单向性&#xff0c;即很难从输出推断出输⼊&…

uniapp scroll-view滚动页面

页面滚动固定距离&#xff08;scrollTop&#xff09; <template><view><button click"Test">测试</button><scroll-view style"height: 100px;" :scroll-top"scrollTop" scroll-y"true" class"scrol…

大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

Cadence Virtuoso添加工艺库、转换工艺库格式

系统环境&#xff1a;Red Hat 操作软件&#xff1a;Virtuoso 工艺库&#xff1a;tsmc18rf 1、准备好工艺库文件&#xff0c;放在任意文件夹内&#xff0c;记住文件路径&#xff1a; 2、打开Virtuoso软件&#xff1a; 在桌面右键打开终端&#xff0c;输入&#xff1a; virtuo…

Web3D 技术发展瓶颈在哪里?

Web3D 技术的发展瓶颈主要集中在以下几个方面&#xff1a; 1、性能和优化&#xff1a;尽管现代浏览器和硬件逐步提高了性能&#xff0c;但高质量的3D渲染仍可能导致性能瓶颈。特别是在移动设备上&#xff0c;图形渲染和计算可能会受到限制。建议合理控制好项目资源量&#xff…