Создание большого pdf без содержимого в основной памяти

Я использую iText для создания очень больших таблиц в формате PDF. Каков наилучший способ создания этих таблиц вместо того, чтобы хранить все содержимое в памяти? Если я просто увеличу приведенный ниже размер в цикле for до миллиона, у меня закончится память, есть ли лучший способ передать его, чем иметь весь контент в памяти?

Я видел этот пост Как напрямую передавать большой контент в PDF с минимальным объемом памяти? Но я хочу знать, какой iText API использовать.

Пример кода:

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

public class SimpleTable11 {
public final static String DEST = "/Users/.../Documents/test23.pdf";

public static void main(String[] args) throws IOException, DocumentException {
    new SimpleTable11().createPdf(DEST);
}

public void createPdf(String dest) throws IOException, DocumentException {

    System.out.println(new Date());
    Document document = new Document();
    PdfWriter.getInstance(document, new FileOutputStream(DEST));
    document.open();
    PdfPTable table = new PdfPTable(23);
    table.setWidths(new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 });
    table.setWidthPercentage(100);
    table.addCell(createCell("Account", 2, 1, Element.ALIGN_JUSTIFIED));
    table.addCell(createCell("Org Id", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Contract Number", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Transaction Type", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Transaction Number", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Transaction Date", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Start Date", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("End Date", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Billing Reference", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Line Description", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Product Name", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Related Invoices", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Monthly Unit Price", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("quantity", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Total Line Tax", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Total Price", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Exchange Rate", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Taxable", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Vat Rate", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("VAT", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Taxable", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("VAT", 2, 1, Element.ALIGN_LEFT));
    table.addCell(createCell("Total Price", 2, 1, Element.ALIGN_LEFT));

    String[] data = { "44445555", "123456", "0105567", "INV", "123456", "10/10/2018", "11/15/2018", "11/20/2050",
            "SO-0000000000-Mento", "Marketing Product", "Marketing Product ", "Marketing Product",
            "Marketing Product", "0.00", "12.56", "300.00", "0.566667345", "12.54", "10.00%", "12.56", "7.58",
            "7.27", "176.67" };
    for (int i = 0; i < 20000; i++) {
        for (int j = 0; j < data.length; j++) {
            table.addCell(createCell(data[j], 1, 1, Element.ALIGN_LEFT));
        }
    }
    document.add(table);
    document.close();
    System.out.println(new Date());
}

public PdfPCell createCell(String content, float borderWidth, int colspan, int alignment) {
    Font font = new Font(FontFamily.HELVETICA, 4, Font.NORMAL);
    PdfPCell cell = new PdfPCell(new Phrase(content, font));
    cell.setBorderWidth(borderWidth);
    cell.setColspan(colspan);
    cell.setHorizontalAlignment(alignment);
    return cell;
}

}

Я не уверен, какую версию itext вы используете, но, может быть, что-то вроде этого? itextpdf.com/en/resources/examples/itext-7/большие таблицы

Zack 10.04.2019 05:36

версия itextpdf 5.5.13

Gowrav 10.04.2019 05:41

@ZackLaVallee, как вы нашли этот код, мне действительно трудно что-либо искать в iText. Также есть ли какие-либо примеры того же в iText, который передает данные непосредственно в pdf при преобразовании HTML в PDF вместо памяти?

Gowrav 10.04.2019 06:01

При использовании PdfPTable используйте его как LargeElement, то есть сначала используйте setComplete(false), затем добавьте некоторый контент (например, 20 строк) в таблицу, затем добавьте таблицу в документ, добавьте еще немного контента, снова добавьте таблицу в документ. , и т. д..., и когда все будет добавлено, используйте setComplete(true) и добавьте снова. Таким образом, данные таблицы не остаются в куче, а по крупицам сериализуются в модуль записи.

mkl 10.04.2019 06:45

Если вы не найдете вариант прямой потоковой передачи, вы всегда можете создать PDF-файл по частям, а затем соединить их вместе, что должно быть проще в памяти. Также может быть разумным то, как вы создаете PDF-файл, но ваши настройки памяти JVM по умолчанию слишком малы. С какой версией Java вы работаете и используете ли вы размер памяти по умолчанию или определенный размер (-DXmx)?

Paul Jowett 10.04.2019 15:30

Спасибо за помощь. Предложение @mkl сработало. Я искал то же самое, что он упомянул, то есть пошаговую сериализацию Mkl, если вы хотите, вы можете опубликовать свой комментарий в качестве ответа, чтобы другие могли извлечь из этого пользу, иногда люди пропускают комментарии.

Gowrav 10.04.2019 16:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
6
1 212
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При использовании объектов PdfPTable с очень большим количеством ячеек вы должны использовать этот класс, реализующий LargeElement, который задокументирован как

/**
 * Interface implemented by Element objects that can potentially consume
 * a lot of memory. Objects implementing the LargeElement interface can
 * be added to a Document more than once. If you have invoked setComplete(false),
 * they will be added partially and the content that was added will be
 * removed until you've invoked setComplete(true);
 * @since   iText 2.0.8
 */
public interface LargeElement extends Element

т.е. вы должны сначала использовать

setComplete(false),

затем добавьте некоторый контент (например, 20 строк) в таблицу, затем добавьте таблицу в документ, добавьте еще немного контента, снова добавьте таблицу в документ и т. д., и когда все будет добавлено, используйте

setComplete(true)

и добавьте таблицу еще раз. Таким образом, данные таблицы не остаются в куче, а по крупицам сериализуются и записываются в модуль записи.


Кроме того, есть и другие классы iText, которые реализуют LargeElement. Если у вас есть проблемы с огромным потреблением памяти с iText, вы всегда должны проверять объекты, которые вы добавляете в свой Document: если они реализуют LargeElement, сначала попробуйте перенаправить их в Document по частям, как описано выше.

Другие вопросы по теме