Apache POI Java Excel Производительность для больших таблиц - PullRequest
11 голосов
/ 13 мая 2011

У меня есть электронная таблица, которую я пытаюсь прочитать с помощью POI (у меня есть форматы xls и xlsx), но в этом случае проблема связана с файлом xls. Моя электронная таблица содержит около 10000 строк и 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);

Ответы [ 5 ]

13 голосов
/ 18 декабря 2013

Если вы используете Apache POI для создания большого файла Excel, обратите внимание на следующую строку:

sheet.autoSizeColumn((short) p);

Поскольку это приведет к снижению производительности.

7 голосов
/ 13 мая 2011

Я также провел некоторую обработку с тысячами больших файлов Excel, и, на мой взгляд, POI очень быстр.Загрузка файлов Excel также занимает около 1 минуты в самом Excel.Так что я хотел бы подтвердить, что проблема заключается в коде POI

3 голосов
/ 09 января 2012

Я бы попытался использовать потоковый hssf, также представленный в poi-beta3.Это помогло решить проблемы с памятью в больших таблицах с более чем 1000 столбцами.

1 голос
/ 02 июля 2013

Если вы используете Apache POI для создания большого файла Excel, обратите внимание на sheet.autoSizeColumn ((short) p); линии, потому что это повлияет на производительность.

http://stanicblog.blogspot.sg/2013/07/generate-large-excel-report-by-using.html

1 голос
/ 13 мая 2011

Я провел более детальное профилирование, и похоже, что проблема на самом деле в коде вне POI. Я просто предположил, что это узкое место, но я считаю, что это неправильно.

...