Java8 делает чтение и запись в Excel проще и эффективнее

Java

Apache POI

В развитии бизнеса мы часто сталкиваемся с импортом-экспортом Excel, иApache POIЭто API, обычно используемый разработчиками Java. 【POI.apache.org/components/…

GridExcel

Universal solution for reading and writing simply Excel based on functional programming and POI EventModel

GridExcel — это общее решение для простого чтения и записи Excel, основанное на функциональном программировании Java8 и POI EventModel.

  • На основе POI EventModel при чтении и записи Excel с очень большим объемом данных сокращается использование памяти, чтобы избежать OOM и частого FullGC.
  • Основанный на функциональном программировании, он поддерживает обработку различных сложных ситуаций, таких как связанные объекты, а стоимость обучения низкая.
  • Поддерживает потоковую передачу API, обратите внимание, что кодирование и более простое, интуитивно понятное

EventModel

чтоEventModel? существуетPOI FAQ(Часто задаваемые вопросы)【POI.Apache.org/help/Initiate.Contracts…] Официальное объяснение:

The SS eventmodel package is an API for reading Excel files without loading the whole spreadsheet into memory. It does require more knowledge on the part of the user, but reduces memory consumption by more than tenfold. It is based on the AWT event model in combination with SAX. If you need read-only access, this is the best way to do it.

Пакет SS eventmodel — это API для чтения файлов Excel без загрузки всей электронной таблицы в память. Это требует от пользователя больше знаний, но снижает потребление памяти более чем в десять раз. Он основан на сочетании модели событий AWT (Abstract Window Toolkit) и SAX. Это лучший способ, если вам нужен доступ только для чтения.

функциональное программирование

Говоря о функциональном программировании, мы должны упомянутьЛямбда-выражения, если вы не знаете или не имеете глубокого понимания Lambda в Java8, вы можете прочитать эту статью, размещенную на официальном сайте Oracle, [Woohoo. Сеть Oracle.com/tech…], лично я считаю, что это одна из лучших статей о Java8 Lambda от начального до продвинутого уровня.

Цель функционального программирования состоит в том, чтобы достичь代码块传递, т. е. метод как аргумент между методами. С этой целью с развитием языка Java появляются некоторые решения:

  1. Java 1.0, реализованная с использованием EventModel из Abstract Window Toolkit (AWT), но неуклюжая и непрактичная.
  2. Java 1.1, предлагающая серию «Слушатели»
  3. позже использовать内部类и匿名内部类, но в большинстве случаев они используются только для обработки событий.
  4. Позже было обнаружено, что больше мест будет码块作为对象(Данные на самом деле) не только полезны, но и необходимы, но функциональное программирование на Java все еще неуклюже, и его нужно расширять.
  5. До Java 1.7 в Java был представлен пакет java.lang.invoke, предоставляющий новый механизм для динамического определения целевого метода (вы больше не можете просто полагаться на инструкции вызова байт-кода, закрепленные в виртуальной машине), называемый MethodHandle, который имитирует раздел Word. вызов указателя метода кода, аналогичный C/C++Function Pointer(указатель функции) и ввести инструкцию байт-кода 5-го вызова методаinvokedynamic.
  6. До Java 1.8 на основе инструкций байт-кода, предложенных Java 1.7.invokedynamic, реализовали технологию Lamda, передавали функции в качестве параметров между методами, а Java стала лучше поддерживать функциональное программирование.
  7. Разве уже нельзя использовать отражение? API-интерфейс Reflection тяжеловесен и имеет низкую производительность.

Уведомление:5, 6, 7См. «Углубленное понимание виртуальной машины Java», 2-е издание, 8.3.3 Поддержка языка с динамическим типом.


В процессе использования POI большинство пользователей API часто сталкиваются с двумя проблемами, которые такжеGridExcelпроблема, которую нужно решить.

Вопрос 1. Используйте только простую функцию импорта и экспорта, но структура объекта данных каждого бизнеса отличается, и метод обработки необходимо переписать, что очень хлопотно!

Решение

Извлеките логику обработки Excel и инкапсулируйте ее в класс инструмента.

Состояние упаковки

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

Способ упаковки

Будь то чтение или запись, нам нужно решить отношение сопоставления между столбцами (столбцами) в Excel и объектами данных Java Fields (полями) и передать это отношение сопоставления в качестве параметра (объект сопоставления HashMap или LinkedHashMap) в класс инструмента.

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

Для полей необходимо быть совместимыми сложными ситуациями, следующим образом:

  • Исключение при запросе поля
  • Значение поля или ячейки равно null
  • Значение этого столбца может соответствовать связанному объекту или даже значению поля в связанной коллекции.
  • Значения полей или ячеек требуют специальной обработки, напримерvalue == true?完成:失败;
отражение

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

отражение + аннотация

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

анонимный внутренний класс

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

Функциональный интерфейс (лямбда)

Этот метод основан на инструкции байт-кода 5-го вызова метода.invokeDynamicРеализованный блок кода функции передается напрямую, что хорошо поддерживает сложные ситуации, имеет высокую производительность, более простое написание кода, более лаконичную структуру и нулевое вторжение в код объекта данных.

Вопрос 2. Объем данных, импортируемых или экспортируемых из Excel, относительно велик, поэтому内存溢出или频繁的Full GC, как решить?

Решение

  • Чтение Excel - EventModel
  • Написание Excel - потоковая передача.SXSSFWorkbook

принцип

Использование POI очень распространено для нас, и следующие две концепции должны быть нам знакомы:

  • HSSFWorkbook (обработка .xls для версии 97 (-2007))
  • XSSFWorkbook (обработка 2007 OOXML (.xlsx))

Но дляeventmodelиstreaming.SXSSFWorkbookЕго редко трогают.Они предоставляются POI для решения проблемы использования памяти.low level API(низкоуровневый API), используйте их для чтения и записи в Excel очень больших объемов данных, избегая内存溢出или频繁的Full GC. 【POI.apache.org/components/…

  • eventmodel, используемый для чтения Excel, вместо того, чтобы загружать весь Excel в память, он позволяет пользователюInputStreamКаждый раз, когда вы читаете какую-то информацию, отдавайте ееПерезвониилислушатель, Что касается отказа, хранения или того, как обращаться с этим содержимым, это зависит от пользователя.
  • streaming.SXSSFWorkbook, используемый для написания Excel (это инкапсуляция XSSFWorkbook, поддерживает только .xlsx), черезраздвижное окноДля этого в памяти сохраняется только количество строк, разрешенное скользящим окном, а лишние строки записываются во временный файл при вызовеwrite(OutputStream stream)Когда метод записывает содержимое, оно напрямую записывается из временной памяти в цель.OutputStream.SXSSFWorkbookиспользование будет иметь некоторые ограничения.
    • Only a limited number of rows are accessible at a point in time.
    • Sheet.clone() is not supported.
    • Formula evaluation is not supported

Решения

  • GitHub.com/Лю Хуагуй/…Основан на функциональном программировании Java (Lambda), поддерживает потоковый API, использует среду Java 1.8 или выше, стоимость обучения: Lambda

На самом деле официальный сайт POI дал пользователям пример, но эти инструменты просто делают свой собственный пакет для достижения более удобного использования.


быстрый в использовании

<dependency>
    <groupId>com.github.liuhuagui</groupId>
    <artifactId>gridexcel</artifactId>
    <version>2.2</version>
</dependency>

GridExcel.java

GridExcel.java предоставляет множество статических методов, которые можно использовать напрямую. Конкретные примеры см. в тестовом коде (предоставляются тестовые данные и тестовые файлы):

Потоковое API

/**
  * 业务逻辑处理方式三选一:
  * 1.启用windowListener,并将业务逻辑放在该函数中。
  * 2.不启用windowListener,使用get()方法取回全部数据集合,做后续处理。
  * 3.readFunction函数,直接放在函数中处理 或 使用final or effective final的局部变量存放这写数据,做后续处理。
  * 注意:使用EventModel时readFunction函数的输入为每行的cell值集合List<String>。
  * @throws Exception
  */
 @Test
 public void readXlsxByEventModel() throws Exception {
     InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("2007.xlsx");
     GridExcel.readByEventModel(resourceAsStream,TradeOrder.class,ExcelType.XLSX)
             .window(2,ts -> System.out.println(JSON.toJSONString(ts)))//推荐在这里执行自己的业务逻辑
             .process(cs ->{
                 TradeOrder tradeOrder = new TradeOrder();
                 tradeOrder.setTradeOrderId(Long.valueOf(cs.get(0)));
                 Consultant consultant = new  Consultant();
                 consultant.setConsultantName(cs.get(3));
                 tradeOrder.setConsultant(consultant);
                 tradeOrder.setPaymentRatio(cs.get(16));
                 return tradeOrder;
             },1);
 }
 /**
  * 使用Streaming UserModel写出数据到Excel
  * @throws Exception
  */
 @Test
 public void writeExcelByStreaming() throws Exception {
     GridExcel.writeByStreaming(TradeOrder.class)
             .head(writeFunctionMap())//对象字段到Excel列的映射
             .createSheet()
             .process(MockData.data())//模拟数据。在这里设置业务数据集合。
             .write(FileUtils.openOutputStream(new File("/excel/test.xlsx")));
 }

ReadExcel

ReadExcelByUserModel

Используйте пользовательскую модель для чтения файла Excel.

  • недостаток: Расход памяти большой, и вся информация Excel будет загружена в память перед обработкой.
  • преимущество: Готовый API, простой в использовании и понимании.
  • сцены, которые будут использоваться: Excel может обрабатывать небольшой объем данных.
ReadExcelByEventModel

Используйте модель событий для чтения файла Excel.

  • недостаток: Готового API нет, использование и понимание сложнее, подходит для программистов среднего и продвинутого уровня (одна из целей GridExcel — упростить использование EventModel)
  • преимущество: Очень маленький объем памяти. Вместо того, чтобы загружать весь контент в память в начале, обработка (хранение, использование и удаление) основного контента передается пользователю, и пользователь может настроить функцию мониторинга для обработки этого контента. .
  • сцены, которые будут использоваться: Может обрабатывать большие объемы данных в Excel, избегая OOM и частого FullGC.

WriteExcel

WriteExcelByUserModel

Используйте пользовательскую модель для записи файла Excel.

  • недостаток: Весь сгенерированный объект электронных таблиц будет храниться в памяти, поэтому размер записи Excel ограничен размером кучи.
  • преимущество: Легче в использовании и понимании.
  • сцены, которые будут использоваться: Вы можете написать Excel с небольшим объемом данных.
WriteExcelByStreaming

Используйте API-совместимое потоковое расширение XSSF для записи очень большого файла Excel.

  • недостаток:
    • Поддерживает только XSSF;
    • Sheet.clone() не поддерживается;
    • Оценка формулы не поддерживается;
    • Only a limited number of rows are accessible at a point in time.
  • преимущество: Реализовано через скользящее окно, в памяти сохраняется только содержимое заданного размера строк, лишняя часть выписывается во временный файл, а размер записываемого Excel больше не ограничен размером пространства кучи .
  • сцены, которые будут использоваться: Может писать очень большие файлы Excel.

Issues

Проблемы в процессе использования инструмента, есть функции для добавления или изменений запросов могут упомянуть выпуск автор:GitHub.com/Лю Хуагуй/…

  • Например, если вы хотите добавить расширение стиля для строк и столбцов, отличных от первой строки

Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь с автором: 799600902@qq.com