Excel文件的解析

在应用程序开发的过程中,经常需要使用Excel文件来进行数据的导入导出,所以在java语言实现此类需求时,往往会面临着Excel文件的解析(导入)或(导出)。

在java技术圈里,可以进行Excel文件处理的主流技术包括:Apache POI, JXL,Alibaba EasyExcel等

我们今天主要说说Apache POI技术 和 Alibaba EasyExcel:

Apache POI基于DOM方式解析,将文件直接加载内存,所以速度较快,适合Excel文件数据不大的场景。

Alibaba EasyExcel 采用逐行读取的解析方式,将每一行解析结果以观察者的模式通知处理,所以适合数据量较大的Excel文件解析。

Apache POI是用Java编写的免费开源的跨平台的Java API, Apache POI提供Java程序对Microsoft office格式档案进行读写功能的API开源库。

而我们经常使用开源库内的XSSF解析Excel文件,它里面提供了读写Excel格式文件的功能。

这里就需要提到Workbook接口(代表一个Excel文件),用于创建或解析Excel文件,常见实现类XSSFworkbook;

当我们要解析一个Excel文件时,需要知道它的内部结构,有若干个sheet(工作簿),sheet里有若干行,行里有若干单元格。

读取Excel:

public static void main(String[] args) {
		try (Workbook workbook = new XSSFWorkbook(new FileInputStream("C:\\Users\\Administrator\\Documents\\Tencent Files\\2837047212\\FileRecv\\1627356552686.xlsx"))) {
			//获取工作簿
			Sheet sheet = workbook.getSheetAt(0);
			//方式1
			//遍历工作簿中所有行
			for (Row row : sheet) {
				//按照下标获取当前行的单元格
				Cell cell0 = row.getCell(0);//序号
				Cell cell1 = row.getCell(1);//部门
				Cell cell2 = row.getCell(2);//姓名
				Cell cell3 = row.getCell(3);//职位
				Cell cell4 = row.getCell(4);//身份证号
				
				System.out.println("序号:" + (int)cell0.getNumericCellValue());
				System.out.println("部门:" + cell1.getStringCellValue());
				System.out.println("姓名:" + cell2.getStringCellValue());
				System.out.println("职位:" + cell3.getStringCellValue());
				System.out.println("身份证号:" + cell4.getStringCellValue());
				System.out.println();
			}
			//方法2
//			for (int i = 0; i <= sheet.getLastRowNum(); i++) {
//				Row row = sheet.getRow(i);
//				//按照下标获取当前行的单元格
//				Cell cell0 = row.getCell(0);//序号
//				Cell cell1 = row.getCell(1);//部门
//				Cell cell2 = row.getCell(2);//姓名
//				Cell cell3 = row.getCell(3);//职位
//				Cell cell4 = row.getCell(4);//身份证号
//				
//				System.out.println("序号:" + (int)cell0.getNumericCellValue());
//				System.out.println("部门:" + cell1.getStringCellValue());
//				System.out.println("姓名:" + cell2.getStringCellValue());
//				System.out.println("职位:" + cell3.getStringCellValue());
//				System.out.println("身份证号:" + cell4.getStringCellValue());
//				System.out.println();
//			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

在解析时候,需要传入需要解析的Excel文件的路径(因为它是以流的方式传入,所以会出现异常),然后获取Excel文件里的工作簿,再从工作簿中获取行,再从行获取单元格,层层递进,都通过get方法来获取对应的值;

当我们要去遍历工作簿中所有行或所有单元格时,用foreash或for循环都可以遍历;

创建Excel:

     public static void main(String[] args) {
		try (Workbook workbook = new XSSFWorkbook();
				FileOutputStream out = new FileOutputStream("D:\\20220529\\20220708\\Demo.xlsx")) {
			//创建工作簿Sheet
			Sheet sheet0 = workbook.createSheet("2020数据列表");
			Sheet sheet1 = workbook.createSheet("2021数据列表");
			Sheet sheet2 = workbook.createSheet("2022数据列表");
			//创建数据行Row
			Row row0 = sheet0.createRow(0);
			//创建单元格
			Cell cell0 = row0.createCell(0);
			cell0.setCellValue(UUID.randomUUID().toString());
			Cell cell1 = row0.createCell(1);
			cell1.setCellValue(Math.random() * 1000);
			Cell cell2 = row0.createCell(2);
			cell2.setCellValue(LocalDateTime.now());
			
			workbook.write(out);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

创建工作簿和解析时候类似,首先通过createSheet创建工作簿,再在工作簿中通过createRow创建行,再在行里通过createCell创建单元格,通过set方法将内容写入行和单元格,最后通过workbook里的write方法将所写的内容通过输出流写入所输出的路径。

在一个Excel工作表中创建工作簿,需要先通过输入流将Excel路径读取到控制台,再通过输出流将在控制台上创建好的工作簿写入到这个Excel中,实现代码如下:

 List<String> list = Arrays.asList("妲己","貂蝉","立新","夏侯惇","曹操","马克","百里","鲁班","王昭君");
    	 //读取一个已经存在的Excel文件
    	 try (Workbook workbook = new XSSFWorkbook(new FileInputStream("D:\\20220529\\20220708\\data.xlsx"));
				FileOutputStream out = new FileOutputStream("D:\\20220529\\20220708\\data.xlsx")) {
    		 //在“已经存在的Excel文件”创建新的sheet
    		 Sheet sheet = workbook.createSheet();
    		 //获取格式编码值
    		 DataFormat  dataformat = workbook.createDataFormat();
    		 short dataformatCode = dataformat.getFormat("yyyy年MM月dd日 HH:mm:ss");
    		 short moneydataformat = dataformat.getFormat("¥#,###");
    		 //创建日期格式对象
    		 CellStyle datacellstyle = workbook.createCellStyle();
    		 datacellstyle.setDataFormat(dataformatCode);//设置格式编码值 164
    		//创建货币格式对象
    		 CellStyle moneycellstyle = workbook.createCellStyle();
    		 moneycellstyle.setDataFormat(moneydataformat);//设置格式编码值
    		 //列头
    		 Row row = sheet.createRow(0);
    		 Cell cell0 = row.createCell(0);
    		 cell0.setCellValue("序号");
    		 Cell cell1 = row.createCell(1);
    		 cell1.setCellValue("姓名");
    		 Cell cell2 = row.createCell(2);
    		 cell2.setCellValue("时间");
    		 Cell cell3 = row.createCell(3);
    		 cell3.setCellValue("金额");
    		 
    		 for (int i = 0; i < list.size(); i++) {
				String name = list.get(i);
				//创建行
				Row row1 = sheet.createRow(i+1);
				//创建单元格
				Cell  cell10 = row1.createCell(0);//序号
				cell10.setCellValue(String.valueOf(i+1));
				
				Cell  cell11 = row1.createCell(1);//姓名
				cell11.setCellValue(name);
				
				Cell  cell12 = row1.createCell(2);//日期
				cell12.setCellStyle(datacellstyle);//日期格式对象
				cell12.setCellValue(new Date());
				Cell  cell13 = row1.createCell(3);//红包金额
				cell13.setCellStyle(moneycellstyle);//货币格式对象
				cell13.setCellValue((int)(Math.random() * 100000));
			}
    		 workbook.write(out);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

当我们创建单元格时候,需要指定格式时候,可以调用workbook里的createDataFormat()方法,先获取格式编码值,再通过 workbook里createCellStyle()方法创建格式对象,再setDataFormatjiang 方法将编码值写入,再将格式对象,写入需要指定格式的单元格中。

超大Excel文件的读写:

使用POI写入:使用SXSSFWorkbook进行写入,通过设置SXSSFWorkbook的构造参数,可以设置每次在内存中保存的行数,当达到这个值时候,会将这些数据flush到磁盘上,这样就不会出现内存不足的情况。代码如下:

try (Workbook workbook = new SXSSFWorkbook(100);
				FileOutputStream fos = new FileOutputStream("c:\\test\\temp.xlsx")) {
    Sheet sheet1 = workbook.createSheet();

    for (int i = 0; i <= 1000000; i++) {
        Row row = sheet1.createRow(i);
        Cell cell0 = row.createCell(0);
        cell0.setCellValue(UUID.randomUUID().toString());

        Cell cell1 = row.createCell(1);
        cell1.setCellValue(new Date());
    }

    workbook.write(fos);
} catch (IOException e) {
    e.printStackTrace();
}

使用POI写入超大Excel时候会使cpu急速飙升,导致内存占用过高,这样不仅速率底,对cpu要求也高,所以我们在写入超大Excel文件时候,不推荐使用POI使用SXSSFWorkbook进行写入。我们更偏向于使用EasyExcel来对超大Excel文件进行读写。

使用EasyExcel读写:

public class Demo {
	public static void main(String[] args) {
        // 写入100w
        EasyExcel.write("c:\\test\\run\\easy.xlsx", Order.class)
                 .sheet("订单列表")
                 .doWrite(data());
    }
    
    // 创建100w条订单数据
    private static List<Order> data() {
        List<Order> list = new ArrayList<Order>();
        for (int i = 0; i < 1000000; i++) {
            list.add(new Order());
        }
        return list;
    }
}

写入时,EasyExcel类write方法将文件地址,和实体类传入,再创建工作簿,再通过doWrite()方法将创建的数据传入其中。

读取:

EasyExcel.read("c:\\test\\run\\easy.xlsx", Order.class,new AnalysisEventListener<Order>() {
    @Override
    public void invoke(Order order, AnalysisContext arg1) {
        // 读取每条数据
        orderList.add(order);
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        // 读取到列头
        System.out.println(headMap);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext arg0) {
        // 读取完毕
        System.out.println("END");
    }
}).sheet().doRead();

读取时,将EasyExcel类write方法将文件地址,和实体类传入,再传入AnalysisEventListener<>(){}匿名子类,重写其中的方法,在其中可以读取每条数据,也可以读取列头。

以上就是我对Excel文件解析的理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值