当前位置: 首页 > 面试题库 >

适用于大型电子表格的Apache POI Java Excel性能

夏谦
2023-03-14
问题内容

我有一个要通过POI读取的电子表格(我同时具有xls和xlsx格式),但是在这种情况下,问题出在xls文件上。我的电子表格大约有10,000行75列,读入可能需要几分钟(尽管Excel会在几秒钟内打开)。我正在使用基于事件的读取,而不是将整个文件读取到内存中。我代码的内容如下。现在有点混乱,但这实际上只是一个很长的switch语句,大部分是从POI示例中复制的。

使用事件模型的POI性能如此缓慢通常吗?我有什么要加快速度的吗?我认为几分钟对于我的申请是不可接受的。

    POIFSFileSystem poifs = new POIFSFileSystem(fis);
    InputStream din = poifs.createDocumentInputStream("Workbook");
    try
    {
        HSSFRequest req = new HSSFRequest();
        listener = new FormatTrackingHSSFListener(new HSSFListener() {
            @Override
            public void processRecord(Record rec)
            {
                thisString = null;
                int sid = rec.getSid();
                switch (sid)
                {
                    case SSTRecord.sid:
                        strTable = (SSTRecord) rec;
                        break;
                    case LabelSSTRecord.sid:
                        LabelSSTRecord labelSstRec = (LabelSSTRecord) rec;
                        thisString = strTable.getString(labelSstRec
                                .getSSTIndex()).getString();
                        row = labelSstRec.getRow();
                        col = labelSstRec.getColumn();
                        break;
                    case RKRecord.sid:
                        RKRecord rrk = (RKRecord) rec;
                        thisString = "";
                        row = rrk.getRow();
                        col = rrk.getColumn();
                        break;
                    case LabelRecord.sid:
                        LabelRecord lrec = (LabelRecord) rec;
                        thisString = lrec.getValue();
                        row = lrec.getRow();
                        col = lrec.getColumn();
                        break;
                    case BlankRecord.sid:
                        BlankRecord blrec = (BlankRecord) rec;
                        thisString = "";
                        row = blrec.getRow();
                        col = blrec.getColumn();
                        break;
                    case BoolErrRecord.sid:
                        BoolErrRecord berec = (BoolErrRecord) rec;
                        row = berec.getRow();
                        col = berec.getColumn();
                        byte errVal = berec.getErrorValue();
                        thisString = errVal == 0 ? Boolean.toString(berec
                                .getBooleanValue()) : ErrorConstants
                                .getText(errVal);
                        break;
                    case FormulaRecord.sid:
                        FormulaRecord frec = (FormulaRecord) rec;
                        switch (frec.getCachedResultType())
                        {
                            case Cell.CELL_TYPE_NUMERIC:
                                double num = frec.getValue();
                                if (Double.isNaN(num))
                                {
                                    // Formula result is a string
                                    // This is stored in the next record
                                    outputNextStringRecord = true;
                                }
                                else
                                {
                                    thisString = formatNumericValue(frec, num);
                                }
                                break;
                            case Cell.CELL_TYPE_BOOLEAN:
                                thisString = Boolean.toString(frec
                                        .getCachedBooleanValue());
                                break;
                            case Cell.CELL_TYPE_ERROR:
                                thisString = HSSFErrorConstants
                                        .getText(frec.getCachedErrorValue());
                                break;
                            case Cell.CELL_TYPE_STRING:
                                outputNextStringRecord = true;
                                break;
                        }
                        row = frec.getRow();
                        col = frec.getColumn();
                        break;
                    case StringRecord.sid:
                        if (outputNextStringRecord)
                        {
                            // String for formula
                            StringRecord srec = (StringRecord) rec;
                            thisString = srec.getString();
                            outputNextStringRecord = false;
                        }
                        break;
                    case NumberRecord.sid:
                        NumberRecord numRec = (NumberRecord) rec;
                        row = numRec.getRow();
                        col = numRec.getColumn();
                        thisString = formatNumericValue(numRec, numRec
                                .getValue());
                        break;
                    case NoteRecord.sid:
                        NoteRecord noteRec = (NoteRecord) rec;
                        row = noteRec.getRow();
                        col = noteRec.getColumn();
                        thisString = "";
                        break;
                    case EOFRecord.sid:
                        inSheet = false;
                }
                if (thisString != null)
                {
                    // do something with the cell value 
                }
            }
        });
        req.addListenerForAllRecords(listener);
        HSSFEventFactory factory = new HSSFEventFactory();
        factory.processEvents(req, din);

问题答案:

我还对数千个大型excel文件进​​行了一些处理,我认为POI非常快。在Excel本身中,加载excel文件也花费了大约1分钟。所以我会确认问题出在POI代码之外



 类似资料:
  • 人若自洁,脱离卑贱的事,就必作贵重的器皿,成为圣洁,合乎主用,预备行各样的善事。你要逃避少年的私欲,同那清心祷告主的人追求公义、信德、仁爱、和平。惟有那愚拙无学问的辩论,总要弃绝,因为知道这等事是起争竞的。(2 TIMOTHY 2:21-23) 电子表格 一提到电子表格,可能立刻想到的是excel。殊不知,电子表格“历史悠久”,比Word要长久多了。根据维基百科的记载整理一个简史: VisiCal

  • 我正试图让一个Google表单根据1个表单输入的数据,用多行填充电子表格,如下所示: 表单简单,客户信息最少https://docs.google.com/forms/d/1LrKlVuI7kxVU0lxz70Uu-2Obj4x3qIwe6nS-ErzbCAg/ 输入后,我需要表格在表格(或格式化表格)中输入数据,如下所示:-输入的每个部分(1、2或3)应位于单独的行中,具有相同的客户名称 然后,

  • 本章介绍如何使用Java创建电子表格并对其进行操作。 电子表格是Excel文件中的页面; 它包含具有特定名称的行和列。 完成本章后,您将能够创建电子表格并对其执行读取操作。 创建电子表格 首先,让我们使用前面章节中讨论的引用类创建一个电子表格。 按照上一章的说法,首先创建一个工作簿,然后我们可以继续创建一个工作表。 以下代码段用于创建电子表格。 //Create Blank workbook XS

  • 我正在尝试从多个google电子表格中删除一个特定的表格。 我有一个主电子表格,从所有其他电子表格收集数据。从主电子表格中,我可以在其他电子表格中执行不同类型的操作,如添加工作表、重命名工作表、隐藏和锁定工作表。 但无法删除其他电子表格中的表格。查看了其他线程,但找不到任何解决方法。 这就是我到目前为止得到的。它停在这一排: "fname.delete表(本周);}" 我很感谢大家对我的帮助,因为

  • 我是谷歌脚本的新手,不知道是否有人能帮我。 我有一个共享的谷歌电子表格,基本上是用新的员工信息更新行。 我希望只有当插入这些新员工行时,特定列(比如F列)上的“ABC”字符串匹配时,才会触发电子邮件。基本上,电子邮件触发器会让我们的团队知道如何设置新的员工帐户。 有人能帮我吗?我不知道如何进行字符串匹配,也不知道如何让它专门发送给固定的电子邮件收件人。我已经安装了Python、gspread和gd

  • 我已经通过谷歌官方文档《开发者指南》API中提到的一个简单Java代码成功地在我的Google Drive帐户的现有电子表格中创建了一个新的工作表,但我想通过Java代码在我的Google Drive帐户中创建一个新的电子表格。在链接中,他们没有提到这方面的任何示例代码。我已经在Spreadservice类中看到了不同的可用方法。 如何使用Google电子表格API实现这一点?