当前位置: 首页 > 知识库问答 >
问题:

批量 - 如何在超大的Excel文件中读取前N行数据?

赫连捷
2023-11-06

我的Excel文件大概有3000行,1000列。
我希望在这个海量数据中进行搜索,我尝试了使用POI,也尝试了比如先取出部分行数,如60行,并且在60行内进行搜索。但不论怎么样,我总是会遇到out of memroy的问题。

共有3个答案

甘兴学
2023-11-06

这个问题主要是因为POI的内存管理不太好,POI官方提供了SAX事件驱动模式,可以读取大文件。
EasyExcel也可以解决内存溢出的问题:

// 导入依赖包import com.alibaba.excel.EasyExcel;import com.alibaba.excel.context.AnalysisContext;import com.alibaba.excel.event.AnalysisEventListener;import com.alibaba.excel.metadata.Sheet;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;@Slf4jpublic class ReadExcelDemo {    // 定义要读取的前N行数据的数量    private static final int ROW_COUNT = 1000;    public static void main(String[] args) {        // 定义要读取的Excel文件路径        String fileName = "path/to/excel/file.xlsx";        // 定义存储读取结果的列表        List<Object> dataList = new ArrayList<>();        // 使用EasyExcel读取Excel文件        EasyExcel.read(fileName, new AnalysisEventListener<Object>() {            @Override            public void invoke(Object data, AnalysisContext context) {                // 判断读取的行数是否超过了设定值                if (context.readRowHolder().getRowIndex() <= ROW_COUNT) {                    // 将读取的数据存储到列表中                    dataList.add(data);                } else {                    // 超过设定值后停止读取                    context.interrupt();                }            }            @Override            public void doAfterAllAnalysed(AnalysisContext context) {                log.info("Read {} rows of data from Excel file", context.readRowHolder().getRowIndex());            }        }).sheet().doRead();        // 处理读取结果        // ...    }}

如果可以接受商业软件,可以考虑使用GcExcel。GcExcel 做了相关的处理,优化了内存的使用,不会出问题。同时它的API,使用起来比较简单,API是基于Range(区域),和Excel的概念相似,也有专门的API可以查找或者替换内容。
下面是个示例代码,我们从如下图的Excel文件中进行搜索:

image.png
代码:

public void FindText() {    // 构建 workbook    Workbook wb = new Workbook();    // 打开需要搜索的文件    wb.open("resources/ReplaceExample.xlsx");    // 打开对应的sheet    IWorksheet sheet = wb.getWorksheets().get(0);    FindOptions findOption = new FindOptions();    findOption.setMatchCase(true);    // 获取页面中包含内容的区域    IRange searchRange = sheet.getUsedRange();    // 存储查找到的区域    IRange range = null;    // 循环查找    do {        // 搜索包含++的格子,本例中会搜索出C++的格子区域        range = searchRange.find("++", findOption);        if (range != null) {            // 从查找到的区域中取出格子的值            String findVal = range.getValue().toString();            // 获取到值后,进行相关操作        }    }    while (range != null);}
桂杰
2023-11-06

试试看用hutool的ExcelUtil.readBySax
添加一下maven:

<dependency>    <groupId>cn.hutool</groupId>    <artifactId>hutool-all</artifactId>    <version>5.8.16</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.poi/poi --><dependency>    <groupId>org.apache.poi</groupId>    <artifactId>poi</artifactId>    <version>5.2.4</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml --><dependency>    <groupId>org.apache.poi</groupId>    <artifactId>poi-ooxml</artifactId>    <version>5.2.4</version></dependency>

覆盖实现一下里面的方法:

private RowHandler createRowHandler() {    return new RowHandler() {        @Override        public void handle(int sheetIndex, long rowIndex, List<Object> rowlist) {            //遍历excel的每一行你想做什么,sheetIndex是指定sheet,rowIndex是当前行(从0开始),rowList是行数据            //可以用通过rowIndex来限制你要读取的行范围        }    };}
ExcelUtil.readBySax(file, 0, createRowHandler());
燕朝明
2023-11-06

首先,处理超大的Excel文件时,遇到内存溢出(out of memory)问题是比较常见的。这是因为POI等库会将整个Excel文件加载到内存中,如果文件过大,就会占用大量内存。

如果你只需要读取前N行数据,可以考虑使用Apache的POI-OOXML库,它支持按行读取Excel文件。这样,你只需要将数据一行行地读出,而不需要将整个文件加载到内存中。

下面是一个基本的代码示例:

import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.util.Iterator;public class ReadExcel {    public static void main(String[] args) throws IOException {        // 文件路径        String filePath = "your_excel_file.xlsx";        FileInputStream fis = new FileInputStream(new File(filePath));        // 用WorkbookFactory创建Workbook对象        Workbook workbook = WorkbookFactory.create(fis);        // 得到第一页(sheet)        Sheet sheet = workbook.getSheetAt(0);        // 得到行迭代器        Iterator<Row> rowIterator = sheet.iterator();        int rowCount = 0;        while (rowIterator.hasNext() && rowCount < N) { // N为你想读取的行数            Row row = rowIterator.next();            // 这里你可以获取行中的列数据            // ...            rowCount++;        }    }}

在这个代码中,我们首先打开了一个指向你的Excel文件的FileInputStream。然后我们用WorkbookFactory创建了一个Workbook对象,得到了第一个sheet,然后通过迭代器一行行地读取数据。当达到你设定的行数N时,停止读取。注意,你需要替换你的Excel文件路径以及你想读取的行数N。

 类似资料:
  • 该编码能够读取excel文件中的小数据...但不读取excel文件中的大数据文件....如何进一步修改代码?

  • 问题内容: 我有一个非常大的数据集,我无法读取其中的整个数据集。因此,我正在考虑只读取其中的一个数据块进行训练,但是我不知道该怎么做。任何想法将不胜感激。 问题答案: 如果您只想读取前999,999行(非标题): 如果您只想读取1,000,000 … 1,999,999行 nrows :int,默认值无要读取的文件行数。对读取大文件有用* skiprows :类似于列表或整数的行号,在文件开始处要

  • 问题内容: 我需要一次最多读取N行来读取一个大文件,直到EOF。在Python中最有效的方法是什么?就像是: 问题答案: 一种解决方案是列表理解和分片运算符: 在这之后是行的元组。但是,这会将整个文件加载到内存中。如果您不希望这样做(即文件可能真的很大),则可以使用生成器表达式和itertools包中的另一种解决方案: 是一个生成器对象,它为您提供文件的每一行,并且可以在这样的循环中使用: 两种解

  • 我遵循这个http://blog.kondratev.pro/2015/08/reading-xlsx-on-android-4-and-hopefully.html对其进行了编码。 尝试逐行读取: 但结果却是:

  • 问题内容: 鉴于我知道路径名和行号,因此我尝试提取文件的单行,理想情况下,我希望这样做是在 不读取任何多余文件的情况下进行的 。 出于我在这里使用的目的,这是异步还是同步都没有关系。 我当前的(不良)实现如下所示: 我尝试使用createReadStream进行操作,但是数据事件似乎从未触发。谁能提供直接解决此问题的方法,或者向我指出一些NodeJS文件系统交互文档,该文档比标准库API文档驱动的

  • 问题内容: 我想读取一个非常大的文件的最后n行,而不使用Java将整个文件读入任何缓冲区/内存区域。 我环顾了JDK API和Apache Commons I / O,但无法找到适合此目的的一个。 我在想UNIX中使用tail或更少的方式。我认为他们不会加载整个文件,然后显示文件的最后几行。在Java中也应该有类似的方法。 问题答案: 如果使用,则可以使用和到达文件末尾附近的特定点,然后从那里开始