博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java使用POI读取和写入Excel指南
阅读量:5735 次
发布时间:2019-06-18

本文共 15079 字,大约阅读时间需要 50 分钟。

Java使用POI读取和写入Excel指南

做项目时经常有通过程序读取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 < workbook.getNumberOfSheets(); 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 < rowEnd; 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(".") < 0) { 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

示例程序运行后将会在指定的系统路径下生成 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. 源码下载

原文地址

转载地址:http://yuwzx.baihongyu.com/

你可能感兴趣的文章
nagios监控windows 改了NSclient++默认端口 注意事项
查看>>
干货 | JAVA代码引起的NATIVE野指针问题(上)
查看>>
POI getDataFormat() 格式对照
查看>>
Python 中的进程、线程、协程、同步、异步、回调
查看>>
好的产品原型具有哪些特点?
查看>>
实现java导出文件弹出下载框让用户选择路径
查看>>
刨根问底--技术--jsoup登陆网站
查看>>
OSChina 五一劳动节乱弹 ——女孩子晚上不要出门,发生了这样的事情
查看>>
Spring--通过注解来配置bean
查看>>
pandas 十分钟入门
查看>>
nginx rewrite
查看>>
前端安全系列(一):如何防止XSS攻击?
查看>>
IK分词器安装
查看>>
查看Linux并发连接数
查看>>
你是谁不重要,关键是你跟谁!
查看>>
CSS中规则@media的用法
查看>>
pychecker:分析你的python代码
查看>>
css 默认不显示 之后显示
查看>>
我的友情链接
查看>>
DNS显性+隐性URL转发原理
查看>>