Проверка POI листа EXcel: ошибка нехватки памяти


Я пытаюсь проверить файл excel с помощью java, прежде чем сбрасывать его в базу данных.

Вот мой фрагмент кода, который вызывает ошибку.

try {
        fis = new FileInputStream(file);
        wb = new XSSFWorkbook(fis);
        XSSFSheet sh = wb.getSheet("Sheet1");
        for(int i = 0 ; i < 44 ; i++){
            XSSFCell a1 = sh.getRow(1).getCell(i);
            printXSSFCellType(a1);
        }

    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Вот ошибка, которую я получаю

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.ArrayList.<init>(Unknown Source)
    at java.util.ArrayList.<init>(Unknown Source)
    at org.apache.xmlbeans.impl.values.NamespaceContext$NamespaceContextStack.<init>(NamespaceContext.java:78)
    at org.apache.xmlbeans.impl.values.NamespaceContext$NamespaceContextStack.<init>(NamespaceContext.java:75)
    at org.apache.xmlbeans.impl.values.NamespaceContext.getNamespaceContextStack(NamespaceContext.java:98)
    at org.apache.xmlbeans.impl.values.NamespaceContext.push(NamespaceContext.java:106)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.check_dated(XmlObjectBase.java:1273)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.stringValue(XmlObjectBase.java:1484)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.getStringValue(XmlObjectBase.java:1492)
    at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellImpl.getR(Unknown Source)
    at org.apache.poi.xssf.usermodel.XSSFCell.<init>(XSSFCell.java:105)
    at org.apache.poi.xssf.usermodel.XSSFRow.<init>(XSSFRow.java:70)
    at org.apache.poi.xssf.usermodel.XSSFSheet.initRows(XSSFSheet.java:179)
    at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:143)
    at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:130)
    at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:286)
    at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:159)
    at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:207)
    at com.xls.validate.ExcelValidator.main(ExcelValidator.java:79)

Это прекрасно работает, когда размер xlsx файла меньше 1 МБ.

Я понимаю это потому, что мой xlsx-файл составляет около 5-10 МБ, и POI пытается загрузить весь лист сразу в память JVM

Что может быть возможным обходным путем?

Пожалуйста, помогите.

Спасибо в Вперед!

4 2

4 ответа:

У вас есть два варианта. Вариант №1-увеличьте размер кучи JVM, чтобы Java имела больше доступной памяти. Обработка файлов Excel в POI с помощью кода UserModel основана на DOM, поэтому весь файл (включая анализируемую форму) должен быть буферизован в память. Попробуйте задать вопрос , подобный этому, чтобы получить совет о том, как увеличить помощь.

Вариант №2, который является более рабочим-переключиться на обработку на основе событий (SAX). Это только обрабатывает часть файла за один раз, так что требуется гораздо меньше памяти. Тем не менее, это требует от вас больше работы, поэтому вам, возможно, лучше бросить еще несколько ГБ памяти на проблему - память дешева, а программисты-нет! В таблице howto page есть инструкции о том, как выполнить синтаксический анализ SAX .xlsx файлы, и есть различные примеры файлов, предоставляемых POI Вы можете посмотреть на советы.

.

Кроме того, еще одна вещь-вы, кажется, загружаете файл через поток, что плохо, как это означает еще больше вещей нуждается в буферизации в памяти. Смотрите документациюPOI для получения дополнительной информации об этом , включая инструкции о том, как работать с файлом напрямую.

Использование Event API (HSSF Only).

API событий является более новым, чем пользовательский API. Он предназначен для разработчиков среднего уровня, которые хотят немного изучить низкоуровневые структуры API. Он относительно прост в использовании, но требует базового понимания частей файла Excel (или готовности учиться). Преимущество заключается в том, что вы можете читать XLS с относительно небольшим объемом памяти.

Вот ссылка с подробной информацией о вашей ошибке и о том, как ее исправить: http://javarevisited.blogspot.com/2011/09/javalangoutofmemoryerror-permgen-space.html?m=1.

Ну, давайте я попробую объяснить вашу ошибку:

У java.lang.OutOfMemoryError Есть два варианта. Один в куче Java, а другой в PermGen пространства.

Ваша ошибка может быть вызвана утечкой памяти, низким объемом системной оперативной памяти или очень малым объемом оперативной памяти, выделенной виртуальной машине Java.

Разница между вариантами пространства кучи Java и пространства PermGen заключается в том, что пространство PermGen хранит пулы строк и данных о примитивных типах, таких как int, а также о том, как читать методы и классы, пространство кучи Java работает по-разному. Поэтому, если в вашем проекте много строк или классов и недостаточно выделенной/системной оперативной памяти, вы получите OutOfMemoryError. По умолчанию объем оперативной памяти, который JVM выделяет PermGen, составляет 64 МБ, что является довольно небольшим объемом памяти. Связанные статья объясняет гораздо больше об этой ошибке и предоставляет подробную информацию о том, как это исправить.

Надеюсь, это поможет!

Я тоже столкнулся с той же проблемой ООМ при разборе xlsx-файла...после двух дней борьбы, я, наконец, нашел код ниже, который был действительно идеальным;

Этот код основан на sjxlsx. Он читает xlsx и сохраняет в hssf-листе.

           [code=java] 
            // read the xlsx file
       SimpleXLSXWorkbook = new SimpleXLSXWorkbook(new File("C:/test.xlsx"));

        HSSFWorkbook hsfWorkbook = new HSSFWorkbook();

        org.apache.poi.ss.usermodel.Sheet hsfSheet = hsfWorkbook.createSheet();

        Sheet sheetToRead = workbook.getSheet(0, false);

        SheetRowReader reader = sheetToRead.newReader();
        Cell[] row;
        int rowPos = 0;
        while ((row = reader.readRow()) != null) {
            org.apache.poi.ss.usermodel.Row hfsRow = hsfSheet.createRow(rowPos);
            int cellPos = 0;
            for (Cell cell : row) {
                if(cell != null){
                    org.apache.poi.ss.usermodel.Cell hfsCell = hfsRow.createCell(cellPos);
                    hfsCell.setCellType(org.apache.poi.ss.usermodel.Cell.CELL_TYPE_STRING);
                    hfsCell.setCellValue(cell.getValue());
                }
                cellPos++;
            }
            rowPos++;
        }
        return hsfSheet;[/code]