java - 使用 Java 忽略空白单元格但不忽略行
问题描述
我正在创建一个java程序来上传一个excel文件并使用spring boot将其读取为Json,但是每当我尝试上传我的文件时,它都会显示错误,以及可以做些什么来忽略任何空白单元格而不是行。
{
"timestamp": 1579604789613,
"status": 500,
"error": "Internal Server Error",
"exception": "java.lang.IndexOutOfBoundsException",
"message": "Index: 1, Size: 1",
"path": "/applications/upload"
}
服务等级为
Workbook workbook = WorkbookFactory.create(file.getInputStream());
Sheet sheet = workbook.getSheetAt(0);
Supplier<Stream<Row>> rowStreamSupplier = uploadUtil.getRowStreamSupplier(sheet);
Row headerRow = rowStreamSupplier.get().findFirst().get();
List<String> headerCells = uploadUtil.getStream(headerRow)
.map(Cell::getStringCellValue)
.collect(Collectors.toList());
int colCount = headerCells.size();
return rowStreamSupplier.get()
.skip(1)
.map(row -> {
List<String> cellList = uploadUtil.getStream(row)
.map(Cell::getStringCellValue)
.collect(Collectors.toList());
return uploadUtil.cellIteratorSupplier(colCount)
.get()
.collect(toMap(headerCells::get, cellList::get));
})
.collect(Collectors.toList());
}
实用类
public Supplier<Stream<Row>> getRowStreamSupplier(Iterable<Row> rows) {
return () -> getStream(rows);
}
public <T> Stream<T> getStream(Iterable<T> rows) {
return StreamSupport.stream(rows.spliterator(), false);
}
public Supplier<Stream<Integer>> cellIteratorSupplier(int end) {
return () -> numberStream(end);
}
public Stream<Integer> numberStream(int end) {
return IntStream.range(0, end).boxed();
}
例外是:
java.lang.IndexOutOfBoundsException: Index: 37, Size: 37 at java.util.ArrayList.rangeCheck(ArrayList.java:653) ~[?:1.8.0_111]
at java.util.ArrayList.get(ArrayList.java:429) ~[?:1.8.0_111]
at com.application.lms.application.service.UploadService.lambda$upload$2(UploadService.java:57) ~[classes/:?]
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_111]
解决方案
这IndexOutOfBoundsException
是关于连续内容单元格之间的差异headerCells.size()
和计数。在具体情况下,您有 38 个标题列,但至少有一个内容行只有 37 个内容单元格。真正空的单元格不会被 迭代,Iterable
row
因为它们不存在于 XML 中。这导致 aheaderCells.size()
和 acolCount
为 38 (0 to 37) 但 acellList.size()
仅为 37 (0 to 36) 。所以在 37cellList::get
时失败。IntStream
因此,如果 Excel 工作表可能包含真正的空单元格,那么您不能使用Iterable
row
. 相反,您需要使用Row.getCell
在标题行中具有表示形式的每个列索引。
使用Stream
s 这可以使用IntStream
范围 0 到与您已经收集to单元格colCount
相同的方式来实现。然后,您从中获取单元格,并且从中获取单元格值,该单元格值将返回一个空字符串,用于表示一个空的不存在的单元格。Map
headerCells
cellList
row::getCell
formatter.formatCellValue(cell, evaluator)
例子:
import org.apache.poi.ss.usermodel.*;
import java.io.FileInputStream;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class ReadExcelUsingStreams {
public static void main(String[] args) throws Exception {
DataFormatter formatter = new DataFormatter();
FileInputStream fileIn = new FileInputStream ("Excel.xlsx");
Workbook workbook = WorkbookFactory.create(fileIn);
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Sheet sheet = workbook.getSheetAt(0);
Supplier<Stream<Row>> rowStreamSupplier = UploadUtils.getRowStreamSupplier(sheet);
Row headerRow = rowStreamSupplier.get().findFirst().get();
List<String> headerCells = UploadUtils.getStream(headerRow)
.map(cell -> formatter.formatCellValue(cell, evaluator))
.collect(Collectors.toList());
int colCount = headerCells.size();
List<Map<String, String>> content = rowStreamSupplier.get()
.skip(1)
.map(row -> {
List<String> cellList = UploadUtils.cellIteratorSupplier(colCount)
.get()
.map(row::getCell)
.map(cell -> formatter.formatCellValue(cell, evaluator))
.collect(Collectors.toList());
return UploadUtils.cellIteratorSupplier(colCount)
.get()
.collect(Collectors.toMap(headerCells::get, cellList::get));
})
.collect(Collectors.toList());
System.out.println(content);
workbook.close();
}
}
class UploadUtils {
static Supplier<Stream<Row>> getRowStreamSupplier(Iterable<Row> rows) {
return () -> getStream(rows);
}
static <T> Stream<T> getStream(Iterable<T> iterable) {
return StreamSupport.stream(iterable.spliterator(), false);
}
static Supplier<Stream<Integer>> cellIteratorSupplier(int end) {
return () -> numberStream(end);
}
static Stream<Integer> numberStream(int end) {
return IntStream.range(0, end).boxed();
}
}
推荐阅读
- android - 如何在 Android 中的图像上绘制动画线
- python - 什么决定了字典的项目是否被订购?
- android-studio - 如何在 Windows 上查看 couchbase lite 数据库?
- svn - 为什么在同一版本的 repro 上两个 svnrdump 不同?
- javascript - 如果选择了值,则将多选视为单选
- html - 为什么我的表格不再适用于背景?
- python - 如何匹配字符串,只修改原句的一部分?
- java - 使用异步函数分配全局变量
- postgresql - 错误:列“tickets.created_at”必须出现在 GROUP BY 子句中或在聚合函数中使用
- ruby-on-rails - 测试 ActionController::BadRequest 的异常消息