使用java进行excel的读写,两种excel的区别以及easyexcel的使用

EasyExcel

Excel介绍:

excel的样例:

工作簿:代表这个excel。

工作表:Sheet代表每一张表格

行属性:每一行的数据

列属性:每一列的数据

单元格:最小的属性

写入文件
03年excel和07的区别
07年使用XSSFWorkbook(),生成的Excel后缀名为xlsx
03年使用HSSFWorkbook(),生成的Excel后缀名为xls
少量数据操作:
public class Sheettest {
    String PATH = "E:\\OAsystem\\OfficeAutomatic-System-master\\OfficeAutomatic-System-master";
    @Test
    public void testWriter03() throws Exception {
        //1、创建一个工作簿
        Workbook workbook = new HSSFWorkbook();
        //2、创建一个工作表
        Sheet sheet=workbook.createSheet("狂神观众统计表");
        //3、创建一行.其中0代表第一行   创建了一个(1,1)单元格
        Row row1 = sheet.createRow(0);
        //4、创建一个单元格
        Cell cell11 = row1.createCell(0);
        //5、写入数据
        cell11.setCellValue("今日新增观众");
        //代表第一列的第二个数据
        Cell cell12=row1.createCell(1);
        cell12.setCellValue(666);

        //第二行数据(2,1)
        Row row2=sheet.createRow(1);
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("统计时间");
        //(2,2)
        Cell cell22 = row2.createCell(1);
        String time = new DateTime().toString("yyyy-MM--dd HH:mm:ss");
        cell22.setCellValue(time);

        //生成一张表的信息(IO流)  03 版本使用的xls结尾
        FileOutputStream fileOutputStream=new FileOutputStream(PATH + "狂神观众统计表03.xls");
        //将数据输出到文件中
        workbook.write(fileOutputStream);
        //将其关闭
        fileOutputStream.close();
        System.out.println("输出完毕!");
    }
    @Test
    public void testWriter07() throws Exception {
        //1、创建一个工作簿     07年之后的是XSSF的格式
        Workbook workbook = new XSSFWorkbook();
        //2、创建一个工作表
        Sheet sheet=workbook.createSheet("狂神观众统计表");
        //3、创建一行.其中0代表第一行   创建了一个(1,1)单元格
        Row row1 = sheet.createRow(0);
        //4、创建一个单元格
        Cell cell11 = row1.createCell(0);
        //5、写入数据
        cell11.setCellValue("今日新增观众");
        //代表第一列的第二个数据
        Cell cell12=row1.createCell(1);
        cell12.setCellValue(666);

        //第二行数据(2,1)
        Row row2=sheet.createRow(1);
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("统计时间");
        //(2,2)
        Cell cell22 = row2.createCell(1);
        String time = new DateTime().toString("yyyy-MM--dd HH:mm:ss");
        cell22.setCellValue(time);

        //生成一张表的信息(IO流)  03 版本使用的xls结尾
        FileOutputStream fileOutputStream=new FileOutputStream(PATH + "狂神观众统计表03.xlsx");
        //将数据输出到文件中
        workbook.write(fileOutputStream);
        //将其关闭
        fileOutputStream.close();s
        System.out.println("输出完毕!");
    }
}
大量数据操作

其中使用HSSF来操作:

public void testWriter03bigdata() throws IOException {
    //开始时间
    long begin = System.currentTimeMillis();
    //创建一个薄
    Workbook workbook=new HSSFWorkbook();
    //创建一个表
    Sheet sheet=workbook.createSheet();
    //写入数据
    for (int rowNum = 0;rowNum<65536;rowNum++){
        //每一行的数据写入
        Row row= sheet.createRow(rowNum);
        for(int cellNum = 0;cellNum<10;cellNum++){
            Cell cell=row.createCell(cellNum);
            cell.setCellValue(cellNum);
        }
    }
    System.out.println("over");
    FileOutputStream outputStream = new FileOutputStream(PATH+"testWriter03bigdata.xls");
    workbook.write(outputStream);
    outputStream.close();
    //结束时间
    long end = System.currentTimeMillis();
    System.out.println((double)(end-begin)/1000);
}

注:当其中的数据超过了65536行的之后会报出异常:

我们会选择使用07版的excel来进行操作。

image-20220913231455411

其中使用XSSF来操作:

缺点:写数据时速度非常慢,非常耗内存也会造成内存溢出

优点:可以写入大量的数据。

public void testWriter07bigdata() throws IOException {
    //开始时间
    long begin = System.currentTimeMillis();
    //创建一个薄
    Workbook workbook=new XSSFWorkbook();
    //创建一个表
    Sheet sheet=workbook.createSheet();
    //写入数据
    for (int rowNum = 0;rowNum<100000;rowNum++){
        //每一行的数据写入
        Row row= sheet.createRow(rowNum);
        for(int cellNum = 0;cellNum<10;cellNum++){
            Cell cell=row.createCell(cellNum);
            cell.setCellValue(cellNum);
        }
    }
    System.out.println("over");
    FileOutputStream outputStream = new FileOutputStream(PATH+"testWriter07bigdata1.xlsx");
    workbook.write(outputStream);
    outputStream.close();
    //结束时间
    long end = System.currentTimeMillis();
    System.out.println((double)(end-begin)/1000);
}

大文件书写使用SXSSF提高效率:

使用SXSSFWorkbook()来进行写入,其中会产生一个临时文件,使用一下将临时文件关闭。

//清楚临时文件
((SXSSFWorkbook) workbook).dispose();
public void testWriter07bigdataS() throws IOException {
    //开始时间
    long begin = System.currentTimeMillis();
    //创建一个薄
    Workbook workbook=new SXSSFWorkbook();
    //创建一个表
    Sheet sheet=workbook.createSheet();
    //写入数据
    for (int rowNum = 0;rowNum<100000;rowNum++){
        //每一行的数据写入
        Row row= sheet.createRow(rowNum);
        for(int cellNum = 0;cellNum<10;cellNum++){
            Cell cell=row.createCell(cellNum);
            cell.setCellValue(cellNum);
        }
    }
    System.out.println("over");
    FileOutputStream outputStream = new FileOutputStream(PATH+"testWriter07bigdataS.xlsx");
    workbook.write(outputStream);
    outputStream.close();
    //清楚临时文件
    ((SXSSFWorkbook) workbook).dispose();
    //结束时间
    long end = System.currentTimeMillis();
    System.out.println((double)(end-begin)/1000);
}
读取文件
03版本读取文件:
public void testWriter03() throws Exception {
    //1、获取文件流
    FileInputStream fileInputStream=new FileInputStream(PATH + "OfficeAutomatic-System-master狂神观众统计表03.xls");
    //2、创建一个工作簿,使用excel能操作的,这边斗可以操作
    Workbook workbook = new HSSFWorkbook(fileInputStream);
    //3、得到表
    Sheet sheet=workbook.getSheetAt(0);//这里选择的是第零个表单
    //得到行
    Row row = sheet.getRow(0);
    //得到列
    Cell cell=row.getCell(0);
    //获得数据中的字符串类型:getStringCellValue
    //在读取值的时候一定要注意其中数据的类型
    System.out.println(cell.getStringCellValue());
    fileInputStream.close();

    //2、创建一个工作表,表中的设置
    //Sheet sheet=workbook.createSheet("狂神观众统计表");

}
获取不同值的类型:

其中重点为日期类型的转换。

public void testCellType() throws Exception{
    //1、获取文件流
    FileInputStream fileInputStream=new FileInputStream(PATH + "gz.xlsx");
    //2、创建一个工作簿,使用excel能操作的,这边斗可以操作
    Workbook workbook = new XSSFWorkbook(fileInputStream);
    //选择第一个表来读
    Sheet sheet = workbook.getSheetAt(0);
    //获取标题内容
    Row rowTitle = sheet.getRow(0);
    if(rowTitle!=null){
        //得到一行有多少数量,也就是多少列
        int cellCount=rowTitle.getPhysicalNumberOfCells();
        //读取第一行到每一列
        for(int cellNum=0;cellNum<cellCount;cellNum++)
        {
            Cell cell=rowTitle.getCell(cellNum);
            if(cell!=null){
                //获取到每一列数据的类型
                int cellType=cell.getCellType();
                String cellvalue= cell.getStringCellValue();
                System.out.print(cellvalue+ " | ");
            }

        }
        System.out.print("\n");
    }
    //获取表中内容
    //获取所有的行数
    int rowCount = sheet.getPhysicalNumberOfRows();
    //第0行为标题,所以这里为1
    for (int rowNum = 1;rowNum<rowCount;rowNum++){
        //循环得到每一行数据
        Row rowData = sheet.getRow(rowNum);
        if (rowData!=null){
            //读取列
            int cellCount = rowTitle.getPhysicalNumberOfCells();
            for (int cellNum = 0;cellNum<cellCount;cellNum++){
                System.out.print("["+(rowNum+1)+"-" +(cellNum+1+"]"));
                Cell cell=rowData.getCell(cellNum);
                //匹配列的数据类型
                if(cell!=null){
                    int cellType=cell.getCellType();
                    String cellValue="";

                    switch (cellType){
                        case HSSFCell.CELL_TYPE_STRING://字符串
                            System.out.print("【String】");
                            cellValue=cell.getStringCellValue();
                            break;
                        case HSSFCell.CELL_TYPE_BOOLEAN://布尔
                            System.out.print("【BOOLEAN】");
                            cellValue=String.valueOf(cell.getBooleanCellValue());//进行布尔类型的转换
                            break;
                        case HSSFCell.CELL_TYPE_BLANK://System.out.print("【BLANK】");
                            break;
                        case HSSFCell.CELL_TYPE_NUMERIC://数字(日期和普通的数字)
                            System.out.print("【NUMERIC】");
                            if(HSSFDateUtil.isCellDateFormatted(cell)){
                                System.out.print("【日期】");
                                //取出日期类
                                Date date=cell.getDateCellValue();
                                cellValue=new DateTime(date).toString("yyyy-MM-dd");
                            }else{
                                //不是日期格式可以防止数字过长
                                System.out.print("【转换为字符串输出】");
                                cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                                cellValue=cell.toString();
                            }
                            break;
                        case HSSFCell.CELL_TYPE_ERROR://布尔
                            System.out.print("【错误】");
                            break;
                    }
                    System.out.println(cellValue);
                }
            }

        }

    }
    fileInputStream.close();
}
EasyExcel操作

相关的网址:https://www.yuque.com/easyexcel/doc/write,其中包括了读写相关的操作。

案例:

@Data
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}
/**
 * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
 **/
public class DemoDAO {
    public void save(List<DemoData> list) {
        //持久化操作
        // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
    }
}
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener extends AnalysisEventListener<DemoData> {

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 5;
//    private static final 1 JSON = ;

    List<DemoData> list = new ArrayList<DemoData>();
    /**
     * 缓存的数据
     */
//    private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private DemoDAO demoDAO;

    public DemoDataListener() {
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
        demoDAO = new DemoDAO();
    }

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param demoDAO
     */
    public DemoDataListener(DemoDAO demoDAO) {
        this.demoDAO = demoDAO;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     * 在读取数据的时候会使用
     * DemoData 类型
     * AnalysisContext 分析上下文
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        System.out.println(JSON.toJSONString(data));
//        log.info("解析到一条数据:{}", JSON.toJSONString(data));
//        cachedDataList.add(data);
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
//            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            list.clear();
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", list.size());
        demoDAO.save(list);
        log.info("存储数据库成功!");
    }

//    @Override
//    public void invoke(DemoData demoData, AnalysisContext analysisContext) {
//
//    }
}
public class EasyTest {
    String PATH ="E:\\path\\";
    private List<DemoData> data() {
        List<DemoData> list = new ArrayList<DemoData>();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

    //根据list 写入到excel

    @org.junit.Test
    public void simpleWrite(){
        // 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入

        // 写法1 JDK8+
        // since: 3.0.0-beta1
        String fileName = PATH+"EasyTest.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入 excelType参数即可
        //fileName是一个流,会自动生成xlsx文件
        //DemoData.class其中包括的实体类
        //sheet写入的表名    write (filename,格式类)  doWrite()写入的数据
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

        // 写法2
//        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
//        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
//        // 如果这里想使用03 则 传入excelType参数即可
//        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
//
//        // 写法3:使用 try-with-resources @since 3.1.0

    }

    @org.junit.Test
    public void simpleRead(){
        // 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入

        // 写法1 JDK8+
        // since: 3.0.0-beta1
        String fileName = PATH+"EasyTest.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入 excelType参数即可
        //fileName是一个流,会自动生成xlsx文件
        //DemoData.class其中包括的实体类
        //sheet写入的表名    write (filename,格式类)  doWrite()写入的数据
//        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

        EasyExcel.read(fileName,DemoData.class,new DemoDataListener()).sheet().doRead();
        // 写法2
//        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
//        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
//        // 如果这里想使用03 则 传入excelType参数即可
//        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
//
//        // 写法3:使用 try-with-resources @since 3.1.0

    }
}

读取之后输出的数据:

 EasyExcel.read(fileName,DemoData.class,new DemoDataListener()).sheet().doRead();
        // 写法2
//        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
//        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
//        // 如果这里想使用03 则 传入excelType参数即可
//        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
//
//        // 写法3:使用 try-with-resources @since 3.1.0

    }
}

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值