Вопрос по java, excel, apache-poi, out-of-memory – исключение java.lang.outofmemory при чтении файла Excel (xlsx) с использованием POI

3

Я занимаюсь разработкой веб-приложения, которое считывает данные из файла Excel (xlsx). Я использую POI для чтения листа Excel. Проблема в том, что когда я пытаюсь прочитать файл Excel, сервер выдает следующую ошибку:

enter image description here

Файл Excel, который я пытаюсь прочитать, имеет размер почти 80 МБ. Любое решение этой проблемы?

На самом деле пользователь загружает файл и приложение после сохранения файла на диск и пытается прочитать файл. Фрагмент кода, который я использую для тестирования:

 File savedFile = new File(file_path);

FileInputStream fis = null;
            try {

                fis = new FileInputStream(savedFile);
                XSSFWorkbook xWorkbook = new XSSFWorkbook(fis);
                XSSFSheet xSheet = xWorkbook.getSheetAt(5);

                Iterator rows = xSheet.rowIterator();
                while (rows.hasNext()) {
                    XSSFRow row = (XSSFRow) rows.next();
                    Iterator cells = row.cellIterator();

                    List data = new ArrayList();
                    while (cells.hasNext()) {
                        XSSFCell cell = (XSSFCell) cells.next();
                        System.out.println(cell.getStringCellValue());
                        data.add(cell);
                    }

                }
            } catch (IOException e) {
                e.printStackTrace();
            } 
да. там должен быть. может случиться так, что размер файла до Gb. Это загруженный пользователем файл или файл на диске? Вы можете вставить свой фрагмент кода для чтения файлов? Pranalee
Похоже, вы пытаетесь прочитать все 80 МБ в буфере, который выбрасывает OOM. Pranalee
Любая альтернатива, чтобы прочитать это в чем-то вроде фрагментов? Khawar Raza

Ваш Ответ

7   ответов
2

-Xmx1024 -Xms1024 к пусковой установке.

@Peter: Это деталь.
Это считается плохой практикой, чтобы установитьXms равноXmx, Делая это, вы в основном не разрешаете JVM изменять размеры пулов памяти и ухудшать управление памятью.
@npe: Ты прав. Это не проблема, если ваше приложение все равно будет использовать много памяти. Но я не знаю, так ли это здесь. В более общем смысле идея состоит в том, чтобы установить Xmx на более высокое значение. Это на самом деле зависит от доступной памяти и размера данных.
1024 байта? возможно ты имел ввиду-Xmx1024m который так же, как-mx1g
Еще одна вещь: значение по умолчанию - 64M, поэтому при сложной обработке больших объемов данных он может довольно быстро выйти из строя.
1

Вы можете попытаться увеличить размер кучи Java.

3

Одна вещь, которая будет иметь небольшое значение, - это открытие файла с самого начала. Если у вас есть файл, передайте его! Использование InputStream требует буферизации всего в памяти, что занимает много места. Поскольку вам не нужно выполнять эту буферизацию, не делайте этого!

Если вы используете последние ночные сборки POI, то это очень просто. Ваш код становится:

File file = new File(file_path);
OPCPackage opcPackage = OPCPackage.open(file);
XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);

В противном случае это очень похоже:

File file = new File(file_path);
OPCPackage opcPackage = OPCPackage.open(file.getAbsolutePath());
XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);

Это освободит вас немного памяти, что может быть достаточно. Если это не так, и если вы не можете увеличить пространство кучи Java, достаточное для того, чтобы справиться с ситуацией, то вам придется прекратить использование XSSF UserModel.

В дополнение к текущей дружественной пользовательской модели, которую вы использовали, POI также поддерживает низкоуровневый способ обработки файлов. Этот способ более низкого уровня сложнее использовать, поскольку у вас нет различных помощников, которым требуется весь файл в памяти. Однако это намного более эффективно использует память, поскольку вы обрабатываете файл потоковым способом. Чтобы начать, посмотритеXSSF и SAX (Event API) раздел с практическими рекомендациями на сайте POI. Попробуйте, а также взгляните на различные примеры.

0

Улучшение вашего текущего подхода может заключаться в том, чтобы прочитать около 100 строк(experiment with this figure to get optimum value) из Excel и сделать пакетное обновление в базе данных. Это будет быстрее.

Также вы можете выполнить некоторые оптимизации в своем коде, переместить создание списка из внешнего цикла(loop for reading row data)

List data = new ArrayList();

Считать содержимое всех ячеек, присутствующих в строке, в строковом буфере (возможно, разделенном «запятой»), а затем добавить его в arraylist"data"

Вы добавляете объект типаXSSFRow Arraylist. Нет смысла хранить весь объект в ячейке Excel. Выньте его содержимое и выбросьте объект.

Позже, перед вставкой содержимого в базу данных, вы можете разделить содержимое ячейки с разделителями и выполнить вставку.

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

1

Я думаю, вам нужно увеличить размер кучи. Вы можете сделать это, отредактировав файл catalina.bat. добавлять-Xms1024m -Xmx1024m кCATALINA_OPTS переменная.

  • Xms = initial java heap size
  • Xmx = maximum java heap size

РЕДАКТИРОВАТЬ: от Catalina.bat


rem   CATALINA_OPTS   (Optional) Java runtime options used when the "start",
rem                   "run" or "debug" command is executed.
rem                   Include here and not in JAVA_OPTS all options, that should
rem                   only be used by Tomcat itself, not by the stop process,
rem                   the version command etc.
rem                   Examples are heap size, GC logging, JMX ports etc.

Я действительно сделал следующие изменения и вставил сегмент файла: ------ если не существует & quot;% CATALINA_BASE% \ conf \ logging.properties & quot; Перейти к noJuliConfig set LOGGING_CONFIG = -Djava.util.logging.config.file = & quot;% CATALINA_BASE% \ conf \ logging.properties & quot; : noJuliConfig set JAVA_OPTS =% JAVA_OPTS%% LOGGING_CONFIG%, если не & quot;% LOGGING_MANAGER% & quot; == & quot; & quot; goto noJuliManager set LOGGING_MANAGER = -Djava.util.logging.manager = org.apache.juli.ClassLoaderLogManager: noJuliManager set JAVA_OPTS =% - Xms1024m -Xmx1024m%% LOGGING_MANAGER% повторно ----- Выполнить команду ---------------------------------- Это нормально? Khawar Raza
Вы перезапустили службу Tomcat?
должна быть строчкаset JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%изменить наset JAVA_OPTS=%JAVA_OPTS% -Xmx1024m - Xms1024m %LOGGING_CONFIG%
спасибо, но с той же проблемой. Даже я увеличил эти значения до 2048. Мой файл Excel имеет размер 80 МБ. Khawar Raza
Я открыл файл catalina.bat. Я нашел две-три записи для JAVA_POSTS. Какой из них редактировать? Khawar Raza
0

Я решил проблему путем изменения реализации. На самом деле сначала я выбирал все данные из файла Excel, и данные хранились в типе ArrayList. После этого я вставлял данные в БД, и это было настоящей проблемой. Сейчас я не храню данные вообще. Когда я получаю одну запись из ResultSet, я немедленно вставляю ее в БД, а не сохраняю в arraylist. Я знаю, что одна за другой вставка не очень хороший подход, но пока я использую этот подход. В будущем, если я найду лучший, я определенно переключусь на этот. Спасибо всем.

-1

Вам лучше хранить их в файле и попытаться загрузить их в базу данных в конце. Это позволит избежать одиночной вставки

это должен быть комментарий.

Похожие вопросы