首页 > 解决方案 > 使用 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] 

标签: javaapache-poi

解决方案


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在标题行中具有表示形式的每个列索引。

使用Streams 这可以使用IntStream范围 0 到与您已经收集to单元格colCount相同的方式来实现。然后,您从中获取单元格,并且从中获取单元格值,该单元格值将返回一个空字符串,用于表示一个空的不存在的单元格。Map headerCellscellListrow::getCellformatter.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();
 }
}

推荐阅读