Поток рабочей книги POI в выходной поток сервлета
Я создаю очень большую книгу POI на моем веб-сервере. Сохранение всей рабочей книги в памяти не будет масштабироваться для нескольких одновременных запросов. Есть ли способ, которым я могу постепенно записывать книгу в выходной поток сервлета. Это должно сократить время отклика, а также повысить эффективность памяти процесса.
Ответы
Ответ 1
Если вы собираетесь генерировать Excel 2007 (xslx), вы можете адаптировать подход BigGridDemo.java, как описано здесь: http://web.archive.org/web/20110821054135/http://www.realdevelopers.com/blog/code/excel
Решение состоит в том, чтобы POI сгенерировать контейнер xslx только в качестве шаблона и передать фактические данные электронных таблиц в виде XML в поток вывода zip. После этого оптимизируется генерация XML.
Ответ 2
К сожалению, это невозможно, если нет средств последовательных данных. Я бы предложил искать другой формат, например. CSV или XML. Оба они могут быть выписаны последовательно. Если он поступает из БД, его можно даже сделать более эффективным, поскольку у достойного БД есть встроенные средства для эффективного экспорта в эти форматы. Вам просто нужно передать байты с одной на другую.
Ответ 3
Ситуация значительно улучшилась, так как остальные ответы были написаны - потоковая передача теперь является частью Apache Poi.
См. SXSSFWorkbook класс, а здесь. Он использует потоковое окно над листом, сбрасывая старые строки за окном во временные файлы.
Это основано на подходе BigGridDemo
, который используется в hlg answer, но теперь является частью официального распространения.
Вот пример из документации:
public static void main(String[] args) throws Throwable {
// keep 100 rows in memory, exceeding rows will be flushed to disk
SXSSFWorkbook wb = new SXSSFWorkbook(100);
Sheet sh = wb.createSheet();
for(int rownum = 0; rownum < 1000; rownum++){
Row row = sh.createRow(rownum);
for(int cellnum = 0; cellnum < 10; cellnum++){
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue(address);
}
}
// Rows with rownum < 900 are flushed and not accessible
for(int rownum = 0; rownum < 900; rownum++){
Assert.assertNull(sh.getRow(rownum));
}
// ther last 100 rows are still in memory
for(int rownum = 900; rownum < 1000; rownum++){
Assert.assertNotNull(sh.getRow(rownum));
}
FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
wb.write(out);
out.close();
// dispose of temporary files backing this workbook on disk
wb.dispose();
}
Ответ 4
Если вы используете JExcel
В нем есть пример кода для чтения кода потока и из сервлета.
http://jexcelapi.sourceforge.net/resources/faq/
Единственный недостаток этого API выглядит так, что он поддерживает только до Excel 2003 включительно.
Использование POI. Не можете ли вы создать файл и передать байты файла в выходной поток сервлета?
Ответ 5
Пробовал ли вы метод write напрямую с HttpServletResponse.getOutputStream()?
Обратите внимание на следующий пример:
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("new sheet");
...
OutputStream out = response.getOutputStream();
wb.write(out);
out.close();