Поток рабочей книги 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();