做项目时经常有通过程序读取Excel数据,或是创建新的Excel并写入数据的需求;

网上很多经验教程里使用的POI版本都比较老了,一些API在新版里已经废弃,这里基于最新的Apache POI 4.0.1版本来总结一下整个读取和写入Excel的过程,希望能帮助到需要的人 ^_^

1. 准备工作

1.1 在项目中引入Apache POI相关类库

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

org.apache.poi

poi

4.0.1

org.apache.poi

poi-ooxml

4.0.1

2. 读取或写入Excel数据

2.1 示例程序结构说明

简单说明一下示例程序的整体结构:ExcelReader.java是实现读取Excel数据功能的类;

ExcelWriter.java是创建新的Excel并向其中写入数据的类;

ExcelDataVO.java封装了读取或写入时每一“行”的数据;

MainTest.java是示例程序的入口类,其中演示了读取和写入Excel数据的整个过程;

2.2 读取数据

示例程序需要从桌面读取 readExample.xlsx 内的数据,readExample.xlsx 的内容如下:

读取Excel时主要调用ExcelReader.java类来读取和解析Excel的具体内容,这里以读取系统文件的形式演示读取过程:(兼容 xls 和 xlsx)

2.2.1 主程序入口类代码:/**

* Author: Dreamer-1

* Date: 2019-03-01

* Time: 10:13

* Description: 示例程序入口类

*/public class MainTest {    public static void main(String[] args) {        // 设定Excel文件所在路径

String excelFileName = "/Users/Dreamer-1/Desktop/myBlog/java解析Excel/readExample.xlsx";        // 读取Excel文件内容

List readResult = ExcelReader.readExcel(excelFileName);

// todo 进行业务操作

}

}

读取和写入时封装每一“行”数据的ExcelDataVO.java代码如下:/**

* Author: Dreamer-1

* Date: 2019-03-01

* Time: 11:33

* Description: 读取Excel时,封装读取的每一行的数据

*/public class ExcelDataVO {    /**

* 姓名

*/

private String name;    /**

* 年龄

*/

private Integer age;    /**

* 居住地

*/

private String location;    /**

* 职业

*/

private String job;    public String getName() {        return name;

}    public void setName(String name) {        this.name = name;

}    public Integer getAge() {        return age;

}    public void setAge(Integer age) {        this.age = age;

}    public String getLocation() {        return location;

}    public void setLocation(String location) {        this.location = location;

}    public String getJob() {        return job;

}    public void setJob(String job) {        this.job = job;

}

}

2.2.2 Excel解析类的代码:/**

* Author: Dreamer-1

* Date: 2019-03-01

* Time: 10:21

* Description: 读取Excel内容

*/public class ExcelReader {    private static Logger logger = Logger.getLogger(ExcelReader.class.getName()); // 日志打印类

private static final String XLS = "xls";    private static final String XLSX = "xlsx";    /**

* 根据文件后缀名类型获取对应的工作簿对象

* @param inputStream 读取文件的输入流

* @param fileType 文件后缀名类型(xls或xlsx)

* @return 包含文件数据的工作簿对象

* @throws IOException

*/

public static Workbook getWorkbook(InputStream inputStream, String fileType) throws IOException {

Workbook workbook = null;        if (fileType.equalsIgnoreCase(XLS)) {

workbook = new HSSFWorkbook(inputStream);

} else if (fileType.equalsIgnoreCase(XLSX)) {

workbook = new XSSFWorkbook(inputStream);

}        return workbook;

}    /**

* 读取Excel文件内容

* @param fileName 要读取的Excel文件所在路径

* @return 读取结果列表,读取失败时返回null

*/

public static List readExcel(String fileName) {

Workbook workbook = null;

FileInputStream inputStream = null;        try {            // 获取Excel后缀名

String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());            // 获取Excel文件

File excelFile = new File(fileName);            if (!excelFile.exists()) {

logger.warning("指定的Excel文件不存在!");                return null;

}            // 获取Excel工作簿

inputStream = new FileInputStream(excelFile);

workbook = getWorkbook(inputStream, fileType);            // 读取excel中的数据

List resultDataList = parseExcel(workbook);            return resultDataList;

} catch (Exception e) {

logger.warning("解析Excel失败,文件名:" + fileName + " 错误信息:" + e.getMessage());            return null;

} finally {            try {                if (null != workbook) {

workbook.close();

}                if (null != inputStream) {

inputStream.close();

}

} catch (Exception e) {

logger.warning("关闭数据流出错!错误信息:" + e.getMessage());                return null;

}

}

}    /**

* 解析Excel数据

* @param workbook Excel工作簿对象

* @return 解析结果

*/

private static List parseExcel(Workbook workbook) {

List resultDataList = new ArrayList<>();        // 解析sheet

for (int sheetNum = 0; sheetNum

Sheet sheet = workbook.getSheetAt(sheetNum);            // 校验sheet是否合法

if (sheet == null) {                continue;

}            // 获取第一行数据

int firstRowNum = sheet.getFirstRowNum();

Row firstRow = sheet.getRow(firstRowNum);            if (null == firstRow) {

logger.warning("解析Excel失败,在第一行没有读取到任何数据!");

}            // 解析每一行的数据,构造数据对象

int rowStart = firstRowNum + 1;            int rowEnd = sheet.getPhysicalNumberOfRows();            for (int rowNum = rowStart; rowNum

Row row = sheet.getRow(rowNum);                if (null == row) {                    continue;

}

ExcelDataVO resultData = convertRowToData(row);                if (null == resultData) {

logger.warning("第 " + row.getRowNum() + "行数据不合法,已忽略!");                    continue;

}

resultDataList.add(resultData);

}

}        return resultDataList;

}    /**

* 将单元格内容转换为字符串

* @param cell

* @return

*/

private static String convertCellValueToString(Cell cell) {        if(cell==null){            return null;

}

String returnValue = null;        switch (cell.getCellType()) {            case NUMERIC:   //数字

Double doubleValue = cell.getNumericCellValue();                // 格式化科学计数法,取一位整数

DecimalFormat df = new DecimalFormat("0");

returnValue = df.format(doubleValue);                break;            case STRING:    //字符串

returnValue = cell.getStringCellValue();                break;            case BOOLEAN:   //布尔

Boolean booleanValue = cell.getBooleanCellValue();

returnValue = booleanValue.toString();                break;            case BLANK:     // 空值

break;            case FORMULA:   // 公式

returnValue = cell.getCellFormula();                break;            case ERROR:     // 故障

break;            default:                break;

}        return returnValue;

}    /**

* 提取每一行中需要的数据,构造成为一个结果数据对象

*

* 当该行中有单元格的数据为空或不合法时,忽略该行的数据

*

* @param row 行数据

* @return 解析后的行数据对象,行数据错误时返回null

*/

private static ExcelDataVO convertRowToData(Row row) {

ExcelDataVO resultData = new ExcelDataVO();

Cell cell;        int cellNum = 0;        // 获取姓名

cell = row.getCell(cellNum++);

String name = convertCellValueToString(cell);

resultData.setName(name);        // 获取年龄

cell = row.getCell(cellNum++);

String ageStr = convertCellValueToString(cell);        if (null == ageStr || "".equals(ageStr)) {            // 年龄为空

resultData.setAge(null);

} else {

resultData.setAge(Integer.parseInt(ageStr));

}        // 获取居住地

cell = row.getCell(cellNum++);

String location = convertCellValueToString(cell);

resultData.setLocation(location);        // 获取职业

cell = row.getCell(cellNum++);

String job = convertCellValueToString(cell);

resultData.setJob(job);        return resultData;

}

}

2.2.3 应用场景补充

一般我们会有这样的应用场景,即:在前台页面的文件上传入口上传本地的Excel文件到后台,后台收到Excel文件后进行解析并做对应的业务操作;

这里假设前台已经有了上传文件的入口,再简单贴一下后台的解析代码;

后台接收前台数据的Controller层代码示例:@PostMapping("/uploadExcel")    public ResponseEntity> uploadImage(MultipartFile file) {        // 检查前台数据合法性

if (null == file || file.isEmpty()) {

logger.warning("上传的Excel商品数据文件为空!上传时间:" + new Date());            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

}        try {            // 解析Excel

List parsedResult = ExcelReader.readExcel(file);            // todo 进行业务操作

return new ResponseEntity<>(HttpStatus.OK);

} catch (Exception e) {

logger.warning("上传的Excel商品数据文件为空!上传时间:" + new Date());            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

}

}

ExcelReader.java中的 readExcel() 方法需要做一定的修改,代码如下:/**

* 读取Excel文件内容

* @param file 上传的Excel文件

* @return 读取结果列表,读取失败时返回null

*/

public static List readExcel(MultipartFile file) {

Workbook workbook = null;        try {            // 获取Excel后缀名

String fileName = file.getOriginalFilename();            if (fileName == null || fileName.isEmpty() || fileName.lastIndexOf(".")

logger.warning("解析Excel失败,因为获取到的Excel文件名非法!");                return null;

}

String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());            // 获取Excel工作簿

workbook = getWorkbook(file.getInputStream(), fileType);            // 读取excel中的数据

List resultDataList = parseExcel(workbook);            return resultDataList;

} catch (Exception e) {

logger.warning("解析Excel失败,文件名:" + file.getOriginalFilename() + " 错误信息:" + e.getMessage());            return null;

} finally {            try {                if (null != workbook) {

workbook.close();

}

} catch (Exception e) {

logger.warning("关闭数据流出错!错误信息:" + e.getMessage());                return null;

}

}

}

2.3 写入数据

写入数据时主要调用ExcelWriter.java来创建Excel工作簿对象并写入数据,这里以写入系统文件数据为例演示写入的过程:

2.3.1 主程序入口类代码/**

* Author: Dreamer-1

* Date: 2019-03-01

* Time: 10:13

* Description: 示例程序入口类

*/public class MainTest {    private static Logger logger = Logger.getLogger(MainTest.class.getName());    public static void main(String[] args) {        // 创建需要写入的数据列表

List dataVOList = new ArrayList<>(2);

ExcelDataVO dataVO = new ExcelDataVO();

dataVO.setName("小明");

dataVO.setAge(18);

dataVO.setLocation("广州");

dataVO.setJob("大学生");

ExcelDataVO dataVO2 = new ExcelDataVO();

dataVO2.setName("小花");

dataVO2.setAge(19);

dataVO2.setLocation("深圳");

dataVO2.setJob("大学生");

dataVOList.add(dataVO);

dataVOList.add(dataVO2);        // 写入数据到工作簿对象内

Workbook workbook = ExcelWriter.exportData(dataVOList);        // 以文件的形式输出工作簿对象

FileOutputStream fileOut = null;        try {

String exportFilePath = "/Users/Dreamer-1/Desktop/myBlog/java解析Excel/writeExample.xlsx";

File exportFile = new File(exportFilePath);            if (!exportFile.exists()) {

exportFile.createNewFile();

}

fileOut = new FileOutputStream(exportFilePath);

workbook.write(fileOut);

fileOut.flush();

} catch (Exception e) {

logger.warning("输出Excel时发生错误,错误原因:" + e.getMessage());

} finally {            try {                if (null != fileOut) {

fileOut.close();

}                if (null != workbook) {

workbook.close();

}

} catch (IOException e) {

logger.warning("关闭输出流时发生错误,错误原因:" + e.getMessage());

}

}

}

}

2.3.2 写入Excel类的代码

ExcelWriter.java类中,你可以根据实际需要替换 CELL_HEADS 列头的信息,然后重写 convertDataToRow 方法,转换你自己的行数据;/**

* Author: Dreamer-1

* Date: 2019-03-01

* Time: 11:09

* Description: 生成Excel并写入数据

*/public class ExcelWriter {    private static List CELL_HEADS; //列头

static{        // 类装载时就载入指定好的列头信息,如有需要,可以考虑做成动态生成的列头

CELL_HEADS = new ArrayList<>();

CELL_HEADS.add("姓名");

CELL_HEADS.add("年龄");

CELL_HEADS.add("居住城市");

CELL_HEADS.add("职业");

}    /**

* 生成Excel并写入数据信息

* @param dataList 数据列表

* @return 写入数据后的工作簿对象

*/

public static Workbook exportData(List dataList){        // 生成xlsx的Excel

Workbook workbook = new SXSSFWorkbook();        // 如需生成xls的Excel,请使用下面的工作簿对象,注意后续输出时文件后缀名也需更改为xls

//Workbook workbook = new HSSFWorkbook();

// 生成Sheet表,写入第一行的列头

Sheet sheet = buildDataSheet(workbook);        //构建每行的数据内容

int rowNum = 1;        for (Iterator it = dataList.iterator(); it.hasNext(); ) {

ExcelDataVO data = it.next();            if (data == null) {                continue;

}            //输出行数据

Row row = sheet.createRow(rowNum++);

convertDataToRow(data, row);

}        return workbook;

}    /**

* 生成sheet表,并写入第一行数据(列头)

* @param workbook 工作簿对象

* @return 已经写入列头的Sheet

*/

private static Sheet buildDataSheet(Workbook workbook) {

Sheet sheet = workbook.createSheet();        // 设置列头宽度

for (int i=0; i

sheet.setColumnWidth(i, 4000);

}        // 设置默认行高

sheet.setDefaultRowHeight((short) 400);        // 构建头单元格样式

CellStyle cellStyle = buildHeadCellStyle(sheet.getWorkbook());        // 写入第一行各列的数据

Row head = sheet.createRow(0);        for (int i = 0; i

Cell cell = head.createCell(i);

cell.setCellValue(CELL_HEADS.get(i));

cell.setCellStyle(cellStyle);

}        return sheet;

}    /**

* 设置第一行列头的样式

* @param workbook 工作簿对象

* @return 单元格样式对象

*/

private static CellStyle buildHeadCellStyle(Workbook workbook) {

CellStyle style = workbook.createCellStyle();        //对齐方式设置

style.setAlignment(HorizontalAlignment.CENTER);        //边框颜色和宽度设置

style.setBorderBottom(BorderStyle.THIN);

style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框

style.setBorderLeft(BorderStyle.THIN);

style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框

style.setBorderRight(BorderStyle.THIN);

style.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框

style.setBorderTop(BorderStyle.THIN);

style.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框

//设置背景颜色

style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());

style.setFillPattern(FillPatternType.SOLID_FOREGROUND);        //粗体字设置

Font font = workbook.createFont();

font.setBold(true);

style.setFont(font);        return style;

}    /**

* 将数据转换成行

* @param data 源数据

* @param row 行对象

* @return

*/

private static void convertDataToRow(ExcelDataVO data, Row row){        int cellNum = 0;

Cell cell;        // 姓名

cell = row.createCell(cellNum++);

cell.setCellValue(null == data.getName() ? "" : data.getName());        // 年龄

cell = row.createCell(cellNum++);        if (null != data.getAge()) {

cell.setCellValue(data.getAge());

} else {

cell.setCellValue("");

}        // 所在城市

cell = row.createCell(cellNum++);

cell.setCellValue(null == data.getLocation() ? "" : data.getLocation());        // 职业

cell = row.createCell(cellNum++);

cell.setCellValue(null == data.getJob() ? "" : data.getJob());

}

}

示例程序运行后将会在指定的系统路径下生成 writeExample.xlsx文件,其内容如下:

2.3.3 应用场景补充

一般写入Excel时会有这样的场景:前台页面上有一个导出按钮,点击后将后台某张表里的数据以Excel的形式导出,导出的Excel文件通过浏览器下载到用户系统中;

这里默认前台页面已经有相应的按钮功能,给出对应的Controller层代码供参考:@GetMapping("/exportExcel")    public void exportExcel(HttpServletRequest request, HttpServletResponse response) {

Workbook workbook = null;

OutputStream out = null;        try {            // todo 根据业务需求获取需要写入Excel的数据列表 dataList

// 生成Excel工作簿对象并写入数据

workbook = ExcelWriter.exportData(dataList);            // 写入Excel文件到前端

if(null != workbook){

String excelName = "示例Excel导出";

String fileName = excelName + DateUtil.format(new Date(), DateUtil.SHORT_DATE) + ".xlsx";

fileName = new String(fileName.getBytes("UTF-8"),"iso8859-1");

response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

response.setContentType("application/x-download");

response.setCharacterEncoding("UTF-8");

response.addHeader("Pargam", "no-cache");

response.addHeader("Cache-Control", "no-cache");

response.flushBuffer();

out = response.getOutputStream();

workbook.write(out);

out.flush();

}

} catch (Exception e) {

logger.WARNING("写入Excel过程出错!错误原因:" + e.getMessage());

} finally {            try {                if (null != workbook) {

workbook.close();

}                if (null != out) {

out.close();

}

} catch (IOException e) {

logger.WARNING("关闭workbook或outputStream出错!");

}

}

}// 前台页面发送请求到后台Controller时的JS代码可参考:var url = "/exportExcel";

window.location=url;

3. 源码下载

java poi写入excel_Java使用POI读取和写入Excel指南相关推荐

  1. java poi解析excel_Java 利用POI 解析Excel

    引入的依赖 org.apache.poi poi 3.16 org.apache.poi poi-ooxml 3.16 简单说明 主要有四个属性,Workbook(工作表),Sheet(表单),Row ...

  2. java 导入导出txt文件_Java读取和写入txt文件

    1 问题描述 对于java的读取和写入txt一直心存疑惑,随着知识的积累,又重新进行学习,对java的文件读写理解更加深刻,在这里将自己的小小经验总结分享给大家.下面是大家了解java流的一个基本框架 ...

  3. 算法-(java)-从文件中读取、写入数据

    1.m的n次幂表示 在算法题中经常遇到10的n次幂,java中计算中,有一个函数,返回double类型,math.pow(m,n),m为基数,n为幂次方.这样打印出结果,会打印出带e的数字,如果想要实 ...

  4. java中pdfbox处理pdf常用方法(读取、写入、合并、拆分、写文字、写图片)

    本篇文档将介绍pdfbox处理pdf常用方法(读取.写入.合并.拆分.写文字.写图片). 图中为pdfbox用到的包 1.读取pdf 方法代码: /*** 读取pdf中文字信息(全部)* @param ...

  5. java poi 解析excel_Java用POI解析excel并获取所有单元格数据

    1.导入POI相关jar包 org.apache.poi jar 2.代码示例 public List getAllExcel(File file, String tableName, String ...

  6. java去除多余excel_java使用poi删除excel中的空行

    根据自己实际操作,poi中lastRowNum方法获取行数的是excel最后有数据的一行,从0开始 而physicalNumberOfRows方法获取的行数是excel最后有数据的一行减去最后一行之前 ...

  7. java mvc 导出excel_Java springMVC POI 导出 EXCEL

    思路 : 将需要导出的数据存放在一个List中 创建一个EXCEL表 注意 XSSFWorkbook 只能操作2007以上的版本,XSSFWorkbook 只能操作2003一下的版本,所以需要的时候可 ...

  8. python读取excel写入mysql pandas_python pandas 读取文件 写入文件excel

    读取数据 import pandas as pd import collections def readLocationCodeForExcel(): read_file = r"test. ...

  9. mongo写入mysql_从mysql读取数据写入mongo

    # coding:utf-8 # Created by qinlin.liu at 2017/3/14 import pymysql import datetime #pymongo说明文档  : h ...

最新文章

  1. 最小径集的算法_机器学习的利器——集成算法
  2. 西工大c语言noj100作业,西工大17秋《C语言程序设计》平时作业
  3. ubuntu下svn命令
  4. 重邮2021计算机复试,2021复试调剂信息七
  5. CRM One Order Appointment里start Date的存储原理
  6. 如何给FormPanel表单中的元素赋值以及获取表单元素值
  7. java wait源码_Java精通并发-透过openjdk源码分析wait与notify方法的本地实现
  8. java类成员方法(成员函数)的初步介绍
  9. 用户需求说明书_「软件项目管理入门」(21) 需求调研和需求分析怎么做?
  10. 计算机等级ms答题演示,计算机等级一级MS Office考试考题:第六套演示文稿题
  11. C# FAQ: const和static readonly有什么区别?
  12. springsecurity登出的配置信息以及登出的认证效果
  13. 失业在家靠做PPT日赚800-1000元,有一门副业真的很重要!
  14. NodeJS启动vue项目的坑
  15. python中摄氏度华氏度相互转换
  16. 医学图像开源数据集汇总
  17. 【云原生 • Kubernetes】k8s功能特性、k8s集群架构介绍
  18. NVIDIA Tesla K80:怪物般的双芯计算卡
  19. [机缘参悟-86]:清心寡欲,世外修行 ?负剑下山,闯荡江湖?
  20. pycharm运行程序时在Python console窗口中运行

热门文章

  1. Asterisk 是什么?
  2. 2020安徽省大学生程序设计大赛题解——A数字排列
  3. linux 搭建Discuz论坛教程-个人实践笔记
  4. lgy -oracle
  5. 【NOIP 2016 提高组】蚯蚓
  6. 怎么权衡不同类型项目的收益产出比 ROI?
  7. 苹果主题商店_盒子电视模拟器电视直播+影视点播!苹果安卓手机影视点播!...
  8. php上传文件到七牛云,如何使用php上传大文件到七牛云储?
  9. Google GWT
  10. getElementsByName、getElementById的简单用法