Excel文件解析

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

不管是对Excel做出何种操作;我们都必须遵从它的顺序以及规律;workbook(接口;代表一个Excel文件)->sheet(工作蒲)->row(行)->cell(单元格);

无论是读还是写都应该遵从这样一个顺序和定律。

例如:

Excel文件(内容未知)的解析如下:

import java.io.FileInputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xddf.usermodel.text.CapsType;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class Test1 {
	public static void main(String[] args) {
		try (Workbook workbook = new XSSFWorkbook(new FileInputStream("D:\\pic\\test.xlsx"))) {
			Sheet sheet = workbook.getSheetAt(0);
			//列头
			Row headrow = sheet.getRow(0);
			//遍历列头单元格
			for(Cell headcell : headrow) {
				System.out.printf(headcell.getStringCellValue() + "\t");
			}
			System.out.println();
			
			//获取数据行
			for(int i = 1 ; i <= sheet.getLastRowNum(); i++) {
				//获取当前行
				Row row = sheet.getRow(i);
				//遍历当前行中所有单元格
				for(Cell cell : row) {
					//获取当前单元格的类型
					CellType cellType = cell.getCellType();
					
					//根据当前单元格类型获取单元格的值
					switch(cellType) {
					case STRING: 
						String strval = cell.getStringCellValue();
						System.out.printf(strval + "\t");
						break;
					case NUMERIC:
						double numval = cell.getNumericCellValue();
						System.out.printf(numval + "\t");
						break;
					}
				}
				System.out.println();
				
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

生成(自己创建一个简单的Excel文件):

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class Test2 {
	public static void main(String[] args) {
		List<String>  list = Arrays.asList("妲己","吕布","孙尚香","刘备","关羽","张飞","赵云"); 
		try (Workbook workbook = new XSSFWorkbook(new FileInputStream("D:\\pic\\test.xlsx"));
				FileOutputStream out = new FileOutputStream("D:\\pic\\test.xlsx")) {
			//在已存在的文件中创建新的Sheet
			Sheet sheet = workbook.createSheet();
			
			//获取格式编码值
			DataFormat dataFormat = workbook.createDataFormat();
			short dateFormatCode = dataFormat.getFormat("yyyy年MM月dd日 HH-mm-ss");
			short moneyFormatCode = dataFormat.getFormat("¥#,###");
			
			//创建日期格式对象
			CellStyle  dateCellStyle = workbook.createCellStyle();
			dateCellStyle.setDataFormat(dateFormatCode);//设置格式编码值
			
			//创建货币格式对象
			CellStyle  moneyCellStyle = workbook.createCellStyle();
			moneyCellStyle.setDataFormat(moneyFormatCode);//设置格式编码值
			for(int i = 0 ; i < list.size();i++) {
				String name = list.get(i);
				
				//创建行
				Row row = sheet.createRow(i+1);
				
				//创建单元格
				Cell cell0 = row.createCell(0);//序号
				cell0.setCellValue(String.valueOf(i + 1));
				Cell cell1 = row.createCell(1);//姓名
				cell1.setCellValue(name);
				Cell cell2 = row.createCell(2);//日期
				cell2.setCellStyle(dateCellStyle);//日期格式对象
				cell2.setCellValue(new Date());
				Cell cell3 = row.createCell(3);//红包金额
				cell3.setCellStyle(moneyCellStyle);
				cell3.setCellValue((int)(Math.random() * 100000));
				
			}
			//写入文件
			workbook.write(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

 输出结果:

 

超大Excele文件的读写(100w):

使用POI写入:(注:可能会出现以内存溢出异常(电脑运存较小)附图;)

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class Test3 {
	public static void main(String[] args) {
		try (Workbook workbook = new SXSSFWorkbook(100);
			FileOutputStream out = new FileOutputStream("D:\\pic\\test.xlsx")){
			//在已存在的文件中创建新的Sheet
			Sheet sheet = workbook.createSheet();
			
			//获取格式编码值
			DataFormat dataFormat = workbook.createDataFormat();
			short dateFormatCode = dataFormat.getFormat("yyyy年MM月dd日 HH-mm-ss");
			short moneyFormatCode = dataFormat.getFormat("¥#,###");
			
			//创建日期格式对象
			CellStyle  dateCellStyle = workbook.createCellStyle();
			dateCellStyle.setDataFormat(dateFormatCode);//设置格式编码值
			
			//创建货币格式对象
			CellStyle  moneyCellStyle = workbook.createCellStyle();
			moneyCellStyle.setDataFormat(moneyFormatCode);//设置格式编码值
			for(int i = 0 ; i < 10000000;i++) {
				String name ="A" + i;
				
				//创建行
				Row row = sheet.createRow(i+1);
				
				//创建单元格
				Cell cell0 = row.createCell(0);//序号
				cell0.setCellValue(String.valueOf(i + 1));
				Cell cell1 = row.createCell(1);//姓名
				cell1.setCellValue(name);
				Cell cell2 = row.createCell(2);//日期
				cell2.setCellStyle(dateCellStyle);//日期格式对象
				cell2.setCellValue(new Date());
				Cell cell3 = row.createCell(3);//红包金额
				cell3.setCellStyle(moneyCellStyle);
				cell3.setCellValue((int)(Math.random() * 100000));
				
			}
			//写入文件
			workbook.write(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

 

 内存溢出:

 

 

使用EasyExcel:

 写入:

import java.util.List;

import com.alibaba.excel.EasyExcel;

public class Test1 {
	public static void main(String[] args) {
		long begin = System.currentTimeMillis();
		 // 写入100w
        EasyExcel.write("D:\\pic\\easy.xlsx", Order.class)
                 .sheet("订单列表")
                 .doWrite(data());
        long end = System.currentTimeMillis();
        System.out.println("共耗时" + (end-begin) + "毫秒");
    }
    
    // 创建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;
    }
	

}

 

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.NumberFormat;

public class Order {
	    @ExcelProperty("订单编号")
		private String orderId; // 订单编号
		
	    @ExcelProperty("支付金额")
		@NumberFormat("¥#,###")
		private Double payment; // 支付金额
		
	    @ExcelProperty(value = "创建日期",converter = LocalDateTimeConverter.class)
		private LocalDateTime creationTime; // 创建时间

		public Order() {
			this.orderId = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmmss"))
					+ UUID.randomUUID().toString().substring(0, 5);
			this.payment = Math.random() * 10000;
			this.creationTime = LocalDateTime.now();
		}

		public String getOrderId() {
			return orderId;
		}

		public void setOrderId(String orderId) {
			this.orderId = orderId;
		}

		public Double getPayment() {
			return payment;
		}

		public void setPayment(Double payment) {
			this.payment = payment;
		}

		public LocalDateTime getCreationTime() {
			return creationTime;
		}

		public void setCreationTime(LocalDateTime creationTime) {
			this.creationTime = creationTime;
		}



		@Override
		public String toString() {
			return "Order [orderId=" + orderId + ", payment=" + payment + ", creationTime=" + creationTime + "]";
		}
		

}

 

package Day1;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

public class LocalDateTimeConverter implements Converter<LocalDateTime> {

	@Override
	public Class<LocalDateTime> supportJavaTypeKey() {
		return LocalDateTime.class;
	}

	@Override
	public CellDataTypeEnum supportExcelTypeKey() {
		return CellDataTypeEnum.STRING;
	}

	@Override
	public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
			GlobalConfiguration globalConfiguration) {
		return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
	}

	@Override
	public CellData<String> convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty,
			GlobalConfiguration globalConfiguration) {
		return new CellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
	}

}

 读取:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

public class Test2 {
	public static void main(String[] args) {
		List<Order> orderList = new ArrayList<Order>();
		
		EasyExcel.read("D:\\pic\\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);
		        super.invokeHeadMap(headMap, context);
		    }

		    @Override
		    public void doAfterAllAnalysed(AnalysisContext arg0) {
		        // 读取完毕
		        System.out.println("Game over");
		    }
		}).sheet().doRead();
		
	  //遍历
	  for(Order order : orderList) {
		System.out.println(order);
	  }
}
}

想比较POI写入来说,EasyExcel更快且一般不会出现内存溢出的情况,对电脑的运存要求不高,所以在面对大数据的读或者写操作时,推荐使用EasyExcel。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值