栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java实现Excel文件读写

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java实现Excel文件读写

目录
    • 一、简介
    • 二、maven依赖
    • 三、工具类ExcelUtil
    • 四、测试
      • 4.1、EmployeeVo
      • 4.2、写入数据到Excel
      • 4.3、从Excel读取数据
    • 结语

一、简介

  HSSFWorkbook XSSFWorkbook SXSSFWorkbook三者的区别

  • HSSFWorkbook:是操作Excel 2003以前(包括2003)的版本,扩展名是.xls,数据限制是65535,超过则内存溢出
  • XSSFWorkbook:是操作Excel 2007后的版本,扩展名是.xlsx,数据限制是1048576行,16384列,超过则内存溢出
  • SXSSFWorkbook:是操作Excel 2007后的版本,扩展名是.xlsx,从POI 3.8版本开始可以持久化到磁盘,减少内存溢出问题

  我们写个工具不仅能直接把简单Java对象数据直接导出到Excel,还能把数据读取成我们需要的简单的Java对象,并且可以根据你的需要选择不同的 Workbook,不用纠结HSSFWorkbook XSSFWorkbook SXSSFWorkbook分别怎么用,本文中 org.apache.poi 使用的版本是 5.0.0

二、maven依赖

pom.xml



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.5.2
         
    
    com.alian
    excel
    0.0.1-SNAPSHOT
    excel
    Java实现Excel文件读写

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter
        

        
            org.apache.poi
            poi
            5.0.0
        

        
            org.apache.poi
            poi-ooxml
            5.0.0
        

        
            org.projectlombok
            lombok
            1.16.14
        

        
            junit
            junit
            4.12
            compile
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


  最重要的依赖就是下面两个

   
       org.apache.poi
       poi
       5.0.0
   

   
       org.apache.poi
       poi-ooxml
       5.0.0
   
三、工具类ExcelUtil

ExcelUtil.java

package com.alian.excel.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
public class ExcelUtil {

    
    public static  List readDataFromExcel(String filePath, Class t, int filterRowNumbers) {
        FileInputStream fis = null;
        ArrayList list = new ArrayList<>();
        try {
            T obj = t.newInstance();
            fis = new FileInputStream(filePath);
            Workbook sheets = WorkbookFactory.create(fis);
            //获取sheet第一页(根据自己需要)
            Sheet sheet = sheets.getSheetAt(0);
            //获取表格的行数
            int totalRowNumber = sheet.getPhysicalNumberOfRows();
            //获取对象的字段列表
            Field[] fields = t.getDeclaredFields();
            for (int i = filterRowNumbers; i < totalRowNumber; i++) {
                //获取一行数据
                Row row = sheet.getRow(i);
//              //变量一行数据的每个单元格,row.getPhysicalNumberOfCells()是单元格的数量
                for (int j = 0, jLen = row.getPhysicalNumberOfCells(); j < jLen; j++) {
                    Cell cell = row.getCell(j);
                    //获取字段
                    Field dataField = fields[j];
                    String startWord = dataField.getName().substring(0, 1);
                    String methodName = "set" + dataField.getName().replace(startWord, startWord.toUpperCase());
                    //获取字段的set方法,dataField.getType()是参数的类型
                    Method method = t.getMethod(methodName, dataField.getType());
                    //反射调用set方法,getValueFromCell是把表格的值转成对应的类型
                    method.invoke(obj, getValueFromCell(dataField, cell));
                }
                list.add(obj);
            }
            return list;
        } catch (Exception e) {
            log.error("从Excel读取数据异常", e);
            return Collections.emptyList();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    
    public static  void exportDataToExcel(Workbook workbook, String sheetName, String[] headerArray, List list, String filePath) {
        //生成一个表格,并命名
        Sheet sheet = workbook.createSheet(sheetName);
        //设置表格默认列宽15个字节
        sheet.setDefaultColumnWidth(15);
        //生成一个头部样式
        CellStyle headerStyle = getCellStyle(workbook, true);
        //生成表格标题
        Row headerRow = sheet.createRow(0);
        headerRow.setHeight((short) 300);

        for (int i = 0, len = headerArray.length; i < len; i++) {
            //创建头部行的一个小单元格
            Cell headerRowCell = headerRow.createCell(i);
            //设置头部单元格的样式
            headerRowCell.setCellStyle(headerStyle);
            //设置头部单元格的值
            headerRowCell.setCellValue(headerArray[i]);
        }
        //获取数据域样式
        CellStyle bodyStyle = getCellStyle(workbook, false);
        FileOutputStream os = null;
        try {
            //将数据放入sheet中
            for (int i = 0, iLen = list.size(); i < iLen; i++) {
                //创建一行,因为头部已经占用一行故需要加1
                Row dataRow = sheet.createRow(i + 1);
                T t = list.get(i);
                //利用反射,根据JavaBean属性的先后顺序,动态调用get方法得到属性的值
                Field[] fields = t.getClass().getDeclaredFields();
                try {
                    for (int j = 0, jLen = fields.length; j < jLen; j++) {
                        //获取单元格第值
                        Cell dataRowCell = dataRow.createCell(j);
                        //获取字段
                        Field dataField = fields[j];
                        String startWord = dataField.getName().substring(0, 1);
                        String methodName = "get" + dataField.getName().replace(startWord, startWord.toUpperCase());
                        //获取对象的get方法
                        Method getMethod = t.getClass().getMethod(methodName);
                        //反射调用get方法
                        Object value = getMethod.invoke(t);
                        //单元格值为String
                        dataRowCell.setCellValue(null == value ? "" : value.toString());
                        dataRowCell.setCellStyle(bodyStyle);
                    }
                } catch (Exception e) {
                    log.error("第【{}】行数据生成异常(下标0开始)", i, e);
                }
            }
            os = new FileOutputStream(filePath);
            workbook.write(os);
            os.flush();
        } catch (Exception e) {
            log.error("生成数据异常", e);
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                log.error("关闭文件异常", e);
            }
        }
    }

    
    public static CellStyle getCellStyle(Workbook workbook, boolean isHeader) {
        CellStyle style = workbook.createCellStyle();
        //设置边框
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        //设置边框颜色
        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        //水平对齐方式
        style.setAlignment(HorizontalAlignment.CENTER);
        //垂直对齐方式
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置字体样式
        Font font = workbook.createFont();
        font.setColor(IndexedColors.BLACK.getIndex());
        font.setFontHeightInPoints((short) 12);
        if (isHeader) {
            //设置背景色
            style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            font.setFontHeightInPoints((short) 14);
            font.setBold(true);
        }
        //把字体应用到当前样式
        style.setFont(font);
        return style;
    }

    
    public static Object getValueFromCell(Field dataField, Cell cell) {
        String fieldTypeStr = dataField.getType().toString();
        if (fieldTypeStr.contains("String")) {
            return cell.getStringCellValue();
        } else if (fieldTypeStr.contains("Integer") || fieldTypeStr.contains("int")) {
            return Integer.parseInt(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("Boolean") || fieldTypeStr.contains("boolean")) {
            return Boolean.getBoolean(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("Double") || fieldTypeStr.contains("double")) {
            return Double.parseDouble(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("float")) {
            return Float.parseFloat(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("Long") || fieldTypeStr.contains("long")) {
            return Long.parseLong(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("char")) {
            return cell.getStringCellValue().charAt(0);
        } else if (fieldTypeStr.contains("LocalTime")) {
            return LocalTime.parse(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("LocalDate")) {
            return LocalDate.parse(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("LocalDateTime")) {
            return LocalDateTime.parse(cell.getStringCellValue());
        } else if (fieldTypeStr.contains("Date")) {
            try {
                return new SimpleDateFormat("yyyy-MM-dd").parse(cell.getStringCellValue());
            } catch (ParseException e) {
                log.error("时间转化异常", e);
            }
        }
        return null;
    }

}

  工具类中使用到了反射的知识,来完成getset方法的操作。

四、测试 4.1、EmployeeVo

EmployeeVo.java

package com.alian.excel.vo;

import lombok.Data;

import java.io.Serializable;
import java.time.LocalDate;

@Data
public class EmployeeVo {
    
    
    private String id;

    
    private String name;

    
    private int age;

    
    private double salary;

    
    private String department;

    
    private LocalDate hireDate;

    
    public EmployeeVo(){

    }

    public EmployeeVo(String id, String name, int age, double salary, String department, LocalDate hireDate) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.department = department;
        this.hireDate = hireDate;
    }
}
4.2、写入数据到Excel

我们写个测试类

    @Test
    public void write() {
        List dataList = new ArrayList<>();
        //仅仅是模拟数据
        for (int i = 0; i < 30; i++) {
            EmployeeVo employeeVo = new EmployeeVo("BAT10012","梁南生",18,20000.0,"研发部",LocalDate.of(2020,2,13));
            dataList.add(employeeVo);
        }
        String sheetName = "员工信息";
        String[] headerArray = new String[]{"员工编号", "员工姓名", "员工年龄", "工资", "部门", "入职时间"};
        String filePath = "C:\myFile\CSDN\Excel\Excel文件写入测试.xls";
        ExcelUtil.exportDataToExcel(new HSSFWorkbook(), sheetName, headerArray, dataList, filePath);
        //ExcelUtil.exportDataToExcel(new XSSFWorkbook(), sheetName, headerArray, dataList, filePath);
        //ExcelUtil.exportDataToExcel(new SXSSFWorkbook(),sheetName, headerArray, dataList, filePath);
    }

运行结果:

如果你用HSSFWorkbook 写入的数据大于65535则会报错

	17:02:37.541 [main] ERROR com.alian.excel.utils.ExcelUtil - 生成数据异常
	java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)
4.3、从Excel读取数据
    @Test
    public void read() {
        String filePath = "C:\myFile\CSDN\Excel\Excel文件写入测试.xls";
        List employeeVos = ExcelUtil.readDataFromExcel(filePath, EmployeeVo.class, 1);
        log.info("读取的数据行数:{}",employeeVos.size());
        for (EmployeeVo employeeVo:employeeVos){
            log.info("{}",employeeVo);
        }
    }

运行结果:

17:00:40.303 [main] INFO - 读取的数据行数:30
17:00:40.306 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.306 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.306 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
17:00:40.307 [main] INFO - EmployeeVo(id=BAT10012, name=梁南生, age=18, salary=20000.0, department=研发部, hireDate=2020-02-13)
结语

  本工具类是针对简单Java对象实现读写的,尽量不要使用继承之类的,假设你的对象实现了序列化接口,可能就要对字段 serialVersionUID进行排除。还有就是各种类型的转换并没有写全(只包括常见类型),包括数据空值处理等,大家可以根据需要进行调整。

  本文是先写入再读取,因为写入时字段的类型是字符串,所以读取的时候会转为对象相应的类型,Excel里的格式本身就是很复杂的,所以使用本工具类时,最好是使用本工具写入的,或者先把数据的格式先转为文本格式再使用。

  如果你对账文件处理,建议还是使用CSV文件,参考:Java实现CSV文件的读写(包含追加内容)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/600749.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号