EsayExcel通过模板动态生成多sheet页报错Sheet index () is out of range问题解决方案

在使用EasyExcel3.3.2版本读取模板生成多sheetExcel时遇到SheetIndex越界异常。为解决此问题,通过POI库动态复制sheet来扩容模板,确保能添加新的sheet页。代码示例展示了如何在查询到业务数据后,根据数据量动态创建sheet,并使用EasyExcel的writeHandler进行样式和内容处理。

问题描述:

通过EasyExcel读取模板生成多sheet页Excel的过程中出现报错

Sheet index (2) is out of range (0..1)

EasyExcel依赖版本:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>3.3.2</version>
</dependency>

在git issue上看到其他低版本依然存在该问题。

使用模板填充的方式进行多sheet填错,报错out of range · Issue #2731 · alibaba/easyexcel · GitHub

解决方案:通过POI动态复制sheet

代码如下:

一、EasyExcel读取模板下载的主要逻辑:

/**
 * 模板下载
 *
 * @param listId    查询业务数据id
 */
public void download(String listId) {
	String fileName = "模板.xlsx";
	String downloadPath = EasyExcelUtil.getExcelWritePath(UUID.randomUUID().toString());
	String writePath = downloadPath + fileName;
    //这一步是查询业务数据
	List<CensusListForm> listFormList = censusListFormService.queryByListId(listId);
	if (CollectionUtils.isEmpty(listFormList)) {
		throw new BusinessException("业务数据为空,无法下载");
	}
    //将业务数据封装成自己定义的MultiSheet类
	List<MultiSheet> sheetList = this.handleSheet(listFormList);
	if (CollectionUtils.isNotEmpty(sheetList)) {
		ExcelWriter excelWriter = null;
		try {
			InputStream stream = new ClassPathResource(missionFillTemplate).getInputStream();
			int capacity = sheetList.size() - EasyExcelUtil.DEFAULT_SHEET_NUM;
			if (capacity > 0) {
				//扩容
				stream = EasyExcelUtil.templateSheetResize(stream, capacity);
			}
			excelWriter = EasyExcelFactory.write(writePath)
					.withTemplate(stream)
					.excelType(ExcelTypeEnum.XLSX)
					.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
					.build();
			ExcelWriter finalExcelWriter = excelWriter;
            //如果模板中只有一个sheet页,这里循环就会报错
			sheetList.forEach(e -> {
				WriteSheet writeSheet = EasyExcelFactory.writerSheet(e.getOrder())
						//动态sheet页名覆盖
						.registerWriteHandler(new CustomSheetNameHandler(e.getOrder(), e.getSheetName()))
						.head(e.getHead())
						//设置导出文档样式
						.registerWriteHandler(EasyExcelUtil.getStyleStrategy())
						.build();
				finalExcelWriter.write(e.getData(), writeSheet);
			});
		} catch (IOException e) {
			log.error("读取模板流报错:{}", e.toString());
			throw new BusinessException("读取模板流报错:", e);
		} finally {
			if (excelWriter != null) {
				excelWriter.finish();
			}
		}
	}
	EasyExcelUtil.download(writePath, fileName);
}

二、MultiSheet类的元素

/**
 * sheet页名
 */
private String sheetName;
/**
 * sheet页排序 从0开始
 */
private Integer order;
/**
 * excel表头
 */
private List<List<String>> head;
/**
 * 数据集合
 */
private List<List<String>> data;

三、通过POI复制sheet页扩容模板

/**
 * 通过POI方式复制sheet页。
 * EasyExel(截止到3.3.2版本)通过模板动态添加sheet页时存在bug:
 * 例如:模板中只有1个sheet页,那么动态添加第2个sheet页或报错Sheet index (1) is out of range (0..0)
 * 【注】默认所有的模板sheet页有3页。只有超过3个sheet才用该方法
 *
 * @param stream   excel模板流
 * @param capacity 额外扩容的大小
 * @return 扩容后的模板流
 */
public static InputStream templateSheetResize(InputStream stream, Integer capacity) {
	if (capacity <= 0) {
		return stream;
	}
	try {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		//通过poi复制出需要的sheet个数的模板
		XSSFWorkbook workbook = new XSSFWorkbook(stream);
		//设置模板的第一个sheet的名称
		for (int i = 1; i <= capacity; i++) {
			//复制模板,得到第3+capacity个sheet
			//定义的模板DEFAULT_SHEET_NUM = 3
			int num = DEFAULT_SHEET_NUM + i;
			workbook.cloneSheet(DEFAULT_SHEET_NUM - 1, "Sheet" + num);
		}
		//写到流里
		workbook.write(bos);
		byte[] bArray = bos.toByteArray();
		return new ByteArrayInputStream(bArray);
	} catch (Exception e) {
		log.error("模板扩充sheet页失败:{}", e.getMessage());
		e.printStackTrace();
	}
	return stream;
}

`IndexError: list index out of range` 错误通常表示尝试访问列表中不存在的索引位置。对于 `iexcel.read(path, sheet, cell)` 方法出现此错误,以下是可能的原因及解决办法: #### 1. `sheet` 索引越界 如果 `sheet` 参数是作为索引来指定工作表的,可能指定的索引超出了实际工作表的数量。 ```python import pandas as pd # 假设使用 pandas 读取 Excel try: path = 'your_file.xlsx' # 获取所有表名 xls = pd.ExcelFile(path) sheet_names = xls.sheet_names # 这里假设 sheet 是索引 sheet_index = 0 if sheet_index < len(sheet_names): df = xls.parse(sheet_names[sheet_index]) print(df) else: print("指定的工作表索引超出范围") except Exception as e: print(f"发生错误: {e}") ``` #### 2. `cell` 引用错误 如果 `cell` 参数用于指定单元格范围,可能引用的单元格在工作表中不存在。例如,指定的行或列超出了工作表的实际范围。 ```python import pandas as pd path = 'your_file.xlsx' sheet_name = 'Sheet1' df = pd.read_excel(path, sheet_name=sheet_name) # 假设 cell 是一个表示单元格的字符串,如 'A1' cell = 'A1' try: row = int(cell[1:]) - 1 col = ord(cell[0].upper()) - ord('A') if row < df.shape[0] and col < df.shape[1]: value = df.iat[row, col] print(value) else: print("指定的单元格超出范围") except Exception as e: print(f"发生错误: {e}") ``` #### 3. 文件内容问题 Excel 文件可能损坏或格式不规范,导致 `iexcel.read` 方法在解析时出现索引越界错误。可以尝试使用其他工具(如 Excel 软件)打开文件,检查文件是否能正常打开和查看内容。如果文件损坏,可以尝试修复或重新生成文件。 #### 4. 库版本问题 `iexcel` 库可能存在版本兼容性问题,导致方法调用时出现错误。可以尝试更新 `iexcel` 库到最新版本,或者查看库的文档和社区论坛,了解是否有类似的问题解决方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值