[![Релиз][release-image]][releases] [![Лицензия][license-image]][license]
EEC (Excel Export Core) — это легковесный и эффективный инструмент для чтения и записи Excel, обладающий такими преимуществами, как небольшой размер библиотеки, небольшое количество кода для интеграции и низкое потребление ресурсов во время выполнения.
Основная цель разработки EEC заключалась в решении проблем Apache POI, таких как высокое потребление памяти, медленная скорость работы и избыточный API. Базовый уровень EEC не зависит от библиотеки POI, все базовые функции реализованы самостоятельно. В действительности EEC зависит только от dom4j
и slf4j
, где dom4j
используется для чтения небольших XML-файлов, а slf4j
обеспечивает унифицированный интерфейс для логирования.
Скриншот использования памяти при чтении и записи 100 000 строк по 29 столбцов с параметрами JVM -Xmx10m -Xms10m
. Для проведения тестирования производительности загрузите eec-benchmark проект.
Китайские пользователи могут посетить Gitee, для создания issue разработчики также будут отвечать в кратчайшие сроки
Добавьте в pom.xml
<dependency>
<groupId>org.ttzero</groupId>
<artifactId>eec</artifactId>
<version>${eec.version}</version>
</dependency>
Использование SimpleSheet для простого экспорта Excel позволяет не определять объекты или Map, а напрямую добавлять значения ячеек для экспорта.
// Подготовка данных для экспорта
List<Object> rows = new ArrayList<>();
rows.add(new String[] {"Столбец 1", "Столбец 2", "Столбец 3"});
rows.add(new int[] {1, 2, 3, 4});
rows.add(new Object[] {5, new Date(), 7, null, "Буква", 9, 10.1243});
new Workbook()
.addSheet(new SimpleSheet<>(rows)) // Добавление простого листа
.writeTo(Paths.get("f:/excel")); // Экспорт в директорию F:/excel
Массив объектов является наиболее распространенным типом листа, при экспорте необходимо добавить аннотацию @ExcelColumn("Название столбца")
для каждого свойства объекта, чтобы указать, что это свойство может быть экспортировано. По умолчанию порядок столбцов соответствует порядку свойств в объекте, но можно переопределить порядок столбцов, указав colIndex
.
// Определение объекта для экспорта
public class Student {
@ExcelColumn("Номер студента")
private int id;
``` @ExcelColumn("Имя")
private String name;
}
// Создание Excel файла с названием "Таблица студентов 1-го класса"
new Workbook("Таблица студентов 1-го класса")
// Добавление листа "Студенты" и указание данных для экспорта, можно добавить несколько листов с помощью addSheet
.addSheet(new ListSheet<>("Студенты", students))
// Указание места для сохранения файла, если экспортируем в файл, можно напрямую указать respone.getOutputStream()
.writeTo(Paths.get("f:/excel"));
Динамическое форматирование и преобразование данных реализуются с помощью @FunctionalInterface
, обычно используется для выделения или выделения цветом важных ячеек или строк. Ниже приведен пример того, как отображать оценки ниже 60 баллов как "Неудовлетворительно" и выделять всю строку оранжевым цветом:
new Workbook("Таблица студентов 1-го класса")
.addSheet(new ListSheet<>("Финальные оценки", students,
new Column("Номер", "id", int.class),
new Column("Имя", "name", String.class),
new Column("Оценка", "score", int.class, n -> (int) n < 60 ? "Неудовлетворительно" : n))
.setStyleProcessor((o, style, sst) ->
o.getScore() < 60 ? sst.modifyFill(style, new Fill(PatternType.solid, Color.orange)) : style)
.writeTo(Paths.get("f:/excel"));
new Workbook()
// Копирование рабочего листа [Cover] из файла [企业名片.xls]
.addSheet(new TemplateSheet(Paths.get("./template/企业名片.xls", "封面")))
// Копирование первого рабочего листа из файла [商品导入模板.xlsx] и добавление данных для экспорта
.addSheet(new TemplateSheet(Paths.get("./template/商品导入模板.xlsx")))
.setData(Entity.mock()) // Установка объекта для соответствующего заполнителя ${*}
// Фрагментарное извлечение данных для соответствующего заполнителя ${list.*}
.setData("list", (i, lastOne) -> scrollQuery(i > 0 ? ((Product)lastOne).getId() : 0))
.writeTo(Paths.get("f:/excel"));
#### 5. Поддержка более точного автоматического изменения ширины столбцов
```java
// Тестовый класс
public static class WidthTestItem {
@ExcelColumn(value = "целое число", format = "#,##0_);[Red]-#,##0_);0_)")
private Integer nv;
@ExcelColumn("строка(en)")
private String sen;
@ExcelColumn("строка(китайский)")
private String scn;
@ExcelColumn(value = "дата и время", format = "yyyy-mm-dd hh:mm:ss")
private Timestamp iv;
}
new Workbook("Автоматическая ширина столбцов")
.setAutoSize(true) // <- Автоматическое изменение ширины столбцов
.addSheet(new ListSheet<>(randomTestData()))
.writeTo(Paths.get("f:/excel"));
EEC использует несколько аннотаций ExcelColumn
для реализации многоуровневых заголовков. Строки или столбцы с одинаковыми именами автоматически объединяются.```java
public static class RepeatableEntry {
@ExcelColumn("номер накладной")
private String orderNo;
@ExcelColumn("адрес получателя")
@ExcelColumn("провинция")
private String rProvince;
@ExcelColumn("адрес получателя")
@ExcelColumn("город")
private String rCity;
@ExcelColumn("адрес получателя")
@ExcelColumn("детали адреса")
private String rDetail;
@ExcelColumn("получатель")
private String recipient;
@ExcelColumn("адрес отправителя")
@ExcelColumn("провинция")
private String sProvince;
@ExcelColumn("адрес отправителя")
@ExcelColumn("город")
private String sCity;
@ExcelColumn("адрес отправителя")
@ExcelColumn("детали адреса")
private String sDetail;
@ExcelColumn("отправитель")
private String sender;
}
#### 7. Легкое создание отчетовТеперь можно использовать обычный ListSheet для экспорта красивых отчетов. Примеры см. в [WIKI](https://github.com/wangguanquan/eec/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B-%D0%B2%D1%8B%D0%B3%D1%80%D0%B0%D0%B4%D0%B0-%D0%B8-%D0%B5%D0%BA%D1%81%D0%BF%D0%BE%D1%80%D1%82)


#### 8. Поддержка 28 предустановленных стилей изображений
При экспорте изображений добавляются встроенные стили для улучшения внешнего вида. Подробнее о стилях изображений см. [1-Экспорт Excel#Экспорт изображений](https://github.com/wangguanquan/eec/wiki/1-%D0%95%D0%BA%D1%81%D0%BF%D0%BE%D1%80%D1%82#%D0%B5%D0%BA%D1%81%D0%BF%D0%BE%D1%80%D1%82-%D0%B8%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B8)

### Примеры чтения
EEC использует статический метод `ExcelReader#read` для чтения файлов. Он поддерживает стандартные потоки, поэтому можно использовать встроенные функции JDK, такие как `map`, `filter` и `collect`, для простого чтения Excel, как если бы это были коллекции. Это значительно снижает издержки обучения.
#### 1. Использование потока
```java
try (ExcelReader reader = ExcelReader.read(Paths.get("./User.xlsx"))) {
// Чтение всех worksheet и вывод
reader.sheets().flatMap(Sheet::rows).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
try (ExcelReader reader = ExcelReader.read(Paths.get("./User.xlsx"))) {
List<User> users = reader.sheet(0) // Чтение первого листа
.header(6) // Указание шестой строки как заголовка
.rows() // Чтение строк данных
.map(row -> row.to(User.class))// Преобразование каждой строки в объект User
.collect(Collectors.toList()); // Сбор данных для дальнейшей обработки
} catch (IOException e) {
e.printStackTrace();
}
```#### 3. Фильтрация и агрегация
EEC поддерживает большинство функций потока. В следующем коде используется `filter` для фильтрации зарегистрированных пользователей с платформой "iOS".
```java
reader.sheet(0).header(6)
.rows()
// Фильтрация пользователей с платформой "iOS"
.filter(row -> "iOS".equals(row.getString("platform")))
.map(row -> row.to(User.class))
.collect(Collectors.toList());
Многоуровневые заголовки можно указать с помощью метода header
, указывая номера строк, которые являются заголовками. Многоуровневые заголовки объединяются с помощью :
.
reader.sheet(0)
.header(1, 2) // <- Указание первой и второй строк как заголовков
.rows()
.map(Row::toMap) // <- Преобразование строки в карту
.forEach(System.out::println);
Ниже представлены данные (данные сгенерированы случайным образом, поэтому результат может отличаться от примера):
Номер накладной | Адрес получателя: область | Адрес получателя: город | Адрес получателя: полный адрес | Получатель | Адрес отправителя: область | Адрес отправителя: город | Адрес отправителя: полный адрес | Отправитель |
---|---|---|---|---|---|---|---|---|
921674764 | 湖北省 | 宜昌市 | xx街4号 | 王** | 江苏省 | 南京市 | xx街5号 | 周** |
1512518776 | 广东省 | 佛山市 | xx街6号 | 王** | 广东省 | 广州市 | xx街7号 | 周** |
1473338301 | 浙江省 | 杭州市 | xx街4号 | 王** | 湖北省 | 黄冈市 | xx街7号 | 周** |
1484573956 | 湖北省 | 武汉市 | xx街4号 | 王** | 江苏省 | 南京市 | xx街9号 | 周** |
1409795643 | 湖北省 | 黄冈市 | xx街3号 | 王** | 江苏省 | 南京市 | xx街1号 | 周**Многократные заголовки будут объединены в формате A1:A2:A3, что позволит объединить данные по номеру накладной, адресу получателя: область, адресу получателя: город, тем самым решая проблему путаницы при наличии двух полей "область" и "город". |
Дополнительная информация о использовании многократных заголовков доступна по ссылке WIKI
Добавьте следующую зависимость в pom.xml, после чего будет обеспечена совместимость с форматом xls, без необходимости добавления каких-либо строк кода.
<dependency>
<groupId>org.ttzero</groupId>
<artifactId>eec-e3-support</artifactId>
<version>${eec-e3-support.version}</version>
</dependency>
Методы чтения xls и xlsx полностью идентичны, внешний код не должен различать форматы, EEC предоставляет одинаковые интерфейсы, а внутренний механизм определяет тип файла по заголовку, что более точно, чем простое определение по расширению файла.
Сравнение совместимости двух инструментов см. таблицу
Пример кода```java // Прямо сохраняем в формат CSV для создания тестового файла, для больших объемов данных можно использовать метод #more для получения данных частями new Workbook() .addSheet(createTestData()) .saveAsCSV() // Указываем формат сохранения как CSV .writeTo(Paths.get("d:\abc.csv"));
Версия 0.5.24 (2025-06-04)
-------------
- Исправлены случаи, когда при чтении файла возникает исключение OOM (#435)Версия 0.5.23 (2025-05-06)
-------------
- Исправлены случаи, когда при чтении изображений возникают исключения из-за определенных специфических настроек
- Исправлены случаи, когда при чтении общих строк возникают исключения
- Исправлены случаи, когда при указании пользовательского заголовка и headerRow=1 заголовок не пропускается
- Исправлены ошибки вычисления конечных координат в методе Dimension#toReferer
- В шаблоне листа добавлен метод useOriginalSheetName для сохранения исходного имени листа
- В методе Dimension#of добавлены новые возможности, когда после двоеточия нет координат, это указывает на конец столбца
Версия 0.5.22 (2025-02-23)
-------------
- Включен режим производительности для повышения скорости экспорта
- Поддержка чтения заметок, xls временно не поддерживает (#418)
- Поддержка кросс-листовых ссылок для проверки данных (#420)
- Улучшено чтение изображений, исключены скрытые и повторяющиеся узлы (#414)
- В шаблоне листа добавлено по умолчанию форматирование датВерсия 0.5.21 (2024-12-24)
-------------
- Улучшена совместимость при преобразовании Excel в CSV для типов времени (#409)
- При преобразовании Excel в CSV сохраняются пустые строки из исходного файла
- Улучшена удобность добавления заметок и открыт доступ к свойствам шрифта заметок
- Поддержка файлов и буферов изображений при экспорте шаблонов
- Исправлены случаи, когда по умолчанию разделитель CSVSheet устанавливается в gst (0x0)
- Исправлены ошибки при экспорте более 57344 заметок (#404)
- Улучшен метод Converter, параметры теперь принимаются в виде строки, столбца и ячейки для удобства расширения[Подробнее...](./CHANGELOG)
[релизы]: https://github.com/wangguanquan/eec/releases
[изображение релиза]: http://img.shields.io/badge/release-0.5.24-blue.svg?style=flat
[лицензия]: http://www.apache.org/licenses/LICENSE-2.0
[изображение лицензии]: http://img.shields.io/badge/license-Apache--2-blue.svg?style=flat
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )