Когда мы хотим экспортировать данные базы данных в файл Excel, если объем данных особенно велик, может потребоваться много памяти, чтобы вызвать OOM. Даже без OOM время ожидания запроса истекло, так как создание файла Excel заняло слишком много времени. В настоящее время требуется функция SXSSF (org.apache.poi.xssf.streaming) POI.
Два формата в Excel
-
Excel 97(-2007) file format
-
Excel 2007 OOXML (.xlsx) file format
HSSF is the POI Project's pure Java implementation of the Excel '97(-2007) file format. XSSF is the POI Project's pure Java implementation of the Excel 2007 OOXML (.xlsx) file format.
HSSF and XSSF provides ways to read spreadsheets create, modify, read and write XLS spreadsheets. They provide:
- low level structures for those with special needs
- an eventmodel api for efficient read-only access
- a full usermodel api for creating, reading and modifying XLS files
Since 3.8-beta3, POI provides a low-memory footprint SXSSF API built on top of XSSF.
SXSSF is an API-compatible streaming extension of XSSF to be used when very large spreadsheets have to be produced, and heap space is limited. SXSSF achieves its low memory footprint by limiting access to the rows that are within a sliding window, while XSSF gives access to all rows in the document. Older rows that are no longer in the window become inaccessible, as they are written to the disk.
In auto-flush mode the size of the access window can be specified, to hold a certain number of rows in memory. When that value is reached, the creation of an additional row causes the row with the lowest index to to be removed from the access window and written to disk. Or, the window size can be set to grow dynamically; it can be trimmed periodically by an explicit call to flushRows(int keepRows) as needed.
Due to the streaming nature of the implementation, there are the following limitations when compared to XSSF:
- Only a limited number of rows are accessible at a point in time.
- Sheet.clone() is not supported.
- Formula evaluation is not supported
SXSSF
Как SXSSF снижает потребление памяти? Это уменьшает использование памяти за счет записи данных во временные файлы, что снижает вероятность ошибок OOM.
// turn off auto-flushing and accumulate all rows in memory
SXSSFWorkbook wb = new SXSSFWorkbook(-1);
Вы также можете указать -1 в конструкторе, чтобы отключить автоматическую запись данных в файл, сохраняя все содержимое данных в памяти.
Хотя здесь и решается проблема OOM памяти, все же необходимо записать все данные во временный файл перед ответом на запрос, а проблема таймаута запроса не решена.
Потоковое
Формат файла Excel 2007 OOXML (.xlsx) по сути является zip-файлом, мы можем поместить.xlsx
Расширение файла изменено на.zip
, затем распакуйте:
$ mv output.xlsx output.zip
$ unzip output.zip
$ tree output/
output/
├── [Content_Types].xml
├── _rels
├── docProps
│ ├── app.xml
│ └── core.xml
└── xl
├── _rels
│ └── workbook.xml.rels
├── sharedStrings.xml
├── styles.xml
├── workbook.xml
└── worksheets
└── sheet1.xml
5 directories, 8 files
Мы видим, что файл Excel содержит вышеуказанные файлы после распаковки, где стили — это формат стиля, который мы определили (включая шрифт, размер текста, цвет, центрирование и другие атрибуты), а каталог рабочих листов — это содержимое наших данных.
Анализируя формат данных, мы можем сами контролировать процесс записи файла xlsx, а запись данных непосредственно в поток ответов вместо временного файла может прекрасно решить проблему тайм-аута запроса.
образец кода:
XSSFWorkbook wb = new XSSFWorkbook()
XSSFCellStyle headerStyle = genHeaderStyle(wb)
sheets.each { sheet ->
def xssfSheet = wb.createSheet(sheet.name)
sheet.setXSSFSheet(xssfSheet)
sheet.setHeaderStyle(headerStyle)
}
File template = genTemplateFile(wb)
ZipOutputStream zos = new ZipOutputStream(responseStream);
ZipFile templateZip = new ZipFile(template);
Enumeration<ZipEntry> templateEntries = templateZip.entries();
try {
while (templateEntries.hasMoreElements()) {
// copy all template content to the ZipOutputStream zos
// except the sheet itself
}
zos.putNextEntry(new ZipEntry(sheetName)); // now the sheet
OutputStreamWriter sheetOut = new OutputStreamWriter(zos, "UTF-8");
try {
sheetOut.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sheetOut.write("<worksheet><sheetData>");
// write the content – rows and cells
sheetOut.write("</sheetData></worksheet>");
} finally { sheetOut.close(); }
} finally { zos.close(); }
Среди них шаблон содержит некоторую индексную информацию, например, какие стили созданы, несколько листов и т. д. Эта информация размещается в верхней части ZIP-файла, а последними являются данные содержимого листа.
Оригинальный адрес моего блога:blog.with000red.com/2018/07/24/…