将大型文本文件数据写入Excel

6
我正在阅读一个文本文件,其中包含一些分隔符。
以下是我的文本文件内容示例:
Avc def efg jksjd 1 2 3 5 3 4 6 0
我逐行读取文本文件,并将其保存在内存中,使用哈希映射将行号作为整数类型的键,并将文本文件的每一行作为List对象。
考虑到这一点,我的映射将存储如下信息:
整数列表
1 [Avc def efg jksjd]
我正在使用Apache POI写入Excel。在使用Apache POI写入Excel时,我遵循以下方法,以下是我的代码片段。
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Sample sheet");
Map<Integer, List<Object>> excelDataHolder = new LinkedHashMap<Integer, List<Object>>();
int rownum = 0;
for (Integer key : keyset) {
            Row row = sheet.createRow(rownum++);
            List<Object> objList = excelHolder.get(key);//excelHolder is my map
            int cellnum = 0;
            for (Object obj : objList) {
                Cell cell = row.createCell(cellnum++);
                    cell.setCellValue((Date) obj);
            }
}

如果要写入Excel的行数/记录较少,这种方法效果很好。但是,如果记录数达到十亿级别,或者文本文件有超过10万行,我认为我的方法会失败,因为createRow和createCell会在堆中创建超过10万个对象。无论使用哪种Java到Excel的API,写入Excel都是基于相同的方法,即集合迭代,如上所示。我也用Aspose做了一些示例,结果Aspose也有同样的问题。

  • 每次调用createRow和createCell是否都会创建新的对象?
  • 如果是,有什么替代方法吗?如何以更好的性能将大量数据写入Excel?
4个回答

3

最近的apache-poi版本包含了sxssf。 Shameless copy from website

SXSSF(包:org.apache.poi.xssf.streaming)是XSSF的API兼容流扩展,用于在需要生成非常大的电子表格且堆空间有限时使用。 SXSSF通过限制访问滑动窗口内的行来实现其低内存占用量,而XSSF则可以访问文档中的所有行。不再在窗口中的旧行变得无法访问,因为它们被写入磁盘。

我曾经用它创建了150万行的电子表格。


2
我将根据Aspose.Cells for Java来回答,因为您也尝试过它。
创建或加载非常大的Excel文件几乎总是需要大量内存。即使您一次读取单行或多行,仍然会将内容写入Workbook实例中,该实例已加载到内存中。
解决方案1(不好且非常有限):增加堆大小,如果允许的最大堆大小适用于您的最大文件,请选择它。
解决方案2(复杂且需要一些手动操作): Excel 2007及更高版本每个工作表允许大约100万行。我建议您为100万行创建一个只有一个工作表的工作簿。也就是说,如果文本文件中有1000万行,则创建10个单独的Excel工作簿。
稍后,手动将它们合并到单个Excel工作簿中。当复制具有如此巨大数据的工作表时,Aspose.Cells会抛出内存不足异常。
下面是创建10个具有100万行的单独Excel文件的代码片段。
import com.aspose.cells.*;
import java.util.*;

public class ExcelLargeTextImport
{
    private static String excelFile = Common.dataDir + "largedata.xlsx";

    public static void main(String args[])
    {
        try
        {
            Common.setLicenses();
            importToExcel();
        }
        catch(Exception ex)
        {
            System.out.println(ex.getMessage());
        }
    }

    private static void importToExcel() throws Exception
    {
        // Process each workbook in a method
        for (int sheetCounter=0 ; sheetCounter<10 ; sheetCounter++)
        {
            saveWorkbook(sheetCounter);
        }
    }

    private static void saveWorkbook(int sheetCounter) throws Exception
    {
        Workbook workbook = new Workbook();
        // Get the first sheet 
        Worksheet worksheet = workbook.getWorksheets().get(0);
        Cells cells = worksheet.getCells();

        // Initialize array list with 1 million records
        ArrayList<String> lines = new ArrayList<String>();
        int rowCount = 1000000;
        for (int i=0 ; i<rowCount ; i++)
        {
            lines.add(i + ";value1;value2;value3");
        }

        long lineNo = 1;
        for (String line : lines)
        {
            // Split the line by delimeter
            String[] values = line.split(";");

            // First cell
            Cell cell = cells.get("A" + lineNo);
            cell.setValue(values[0]);

            // Second cell
            cell = cells.get("B" + lineNo);
            cell.setValue(values[1]);

            // Third cell
            cell = cells.get("C" + lineNo);
            cell.setValue(values[2]);

            // Fourth cell
            cell = cells.get("D" + lineNo);
            cell.setValue(values[2]);

            lineNo++;
        }
        System.out.print(sheetCounter + " ");

        // Saving the Excel file
        workbook.save(excelFile.replace(".xlsx", sheetCounter + ".xlsx"));

        System.out.println("\nExcel file created");
    }
}

PS. 我是Aspose的开发者推广员。


1
为什么不分块读写呢?我可以想到以下方法:
  • 读取你的txt文件的前几行,并像你现在做的那样将信息放入映射中。假设你读取了100行,那么你的映射中就有100个条目。
  • 将这一百个条目写入excel文件,第一次生成excel文件。
  • 清空你的映射或重新初始化。
  • 现在从文本中读取接下来的100行。所以据我所知,没有直接访问第101行而不读取前100行的方法。因此,您可能需要从开头读取文件,但可以避免读取前100行并在映射中创建条目。
  • 现在更新excel文件。我认为你可以使用POI在这个链接上提到的方法来更新excel: Edit existing excel files using jxl api / Apache POI

如果你不断迭代这个过程,你一定会节省内存消耗,尽管我没有看到CPU消耗有很大的区别。

希望对你有所帮助!


0

@ OnlineSolution:应该是一条注释吗? - Jayan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接