Потоковая книга POI в выходной поток сервлета - PullRequest
18 голосов
/ 20 апреля 2010

Я создаю очень большую книгу POI на своем веб-сервере. Хранение всей книги в памяти не будет масштабироваться для нескольких одновременных запросов. Есть ли способ, которым я могу постепенно записывать книгу в поток вывода сервлета. Это должно сократить время отклика, а также повысить эффективность использования памяти процесса.

Ответы [ 5 ]

8 голосов
/ 19 июня 2010

Если вы собираетесь сгенерировать Excel 2007 (xslx), вы можете адаптировать подход BigGridDemo.java, как описано здесь: http://web.archive.org/web/20110821054135/http://www.realdevelopers.com/blog/code/excel

Решение состоит в том, чтобы POI генерировал контейнер xslx только в качестве шаблона и передавал фактические данные электронной таблицы в виде XML в поток вывода zip. Оптимизация генерации XML зависит от вас.

4 голосов
/ 21 апреля 2017

Ситуация значительно улучшилась с тех пор, как были написаны остальные ответы - Streaming теперь является частью Apache Poi.

См. Класс SXSSFWorkbook и документацию здесь . Он использует потоковое окно поверх листа, сбрасывая старые строки за пределами окна во временные файлы.

Это основано на подходе BigGridDemo, используемом в ответе hlg , но теперь является частью официального распространения.

Вот пример из документации:

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();
}
3 голосов
/ 20 апреля 2010

К сожалению, это невозможно, если нет средств для последовательных данных. Я бы посоветовал поискать другой формат, например CSV или XML. Оба могут быть записаны последовательно. Если он поступает из БД, его можно даже сделать более эффективным, поскольку приличная БД имеет встроенные средства для эффективного экспорта в эти форматы. Вы просто должны передавать байты с одной стороны на другую.

0 голосов
/ 20 октября 2010

Пробовали ли вы с помощью метода записи напрямую в HttpServletResponse.getOutputStream ()?

Пожалуйста, посмотрите на следующий пример:

 HSSFWorkbook wb = new HSSFWorkbook();
 HSSFSheet sheet = wb.createSheet("new sheet");
 ...
 OutputStream out = response.getOutputStream();
 wb.write(out);
 out.close();
0 голосов
/ 21 апреля 2010

Если вы используете JExcel Он содержит пример кода для чтения потокового кода в сервлет и из него. http://jexcelapi.sourceforge.net/resources/faq/

Единственный недостаток этого API, похоже, что он поддерживает только до Excel 2003 включительно.

Использование POI - Не можете ли вы создать файл и передать его байты потоку вывода сервлета?

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