Dieser deutsche Artikel behandelt Große PDFs in Delphi mit der HotPDF Direct File API verarbeiten für Teams, die mit Delphi, C++Builder, Lazarus/FPC und losLab-Komponenten arbeiten
Der Fokus liegt auf praxisnahen Entscheidungen, Fallstricken und Prüfpunkten, damit die Lösung im produktiven Einsatz verlässlich bleibt
Was vollständiges Laden bringt, und was es kostet
Ein Dokument mit zu laden bringt zufälligen Zugriff auf alles: jede Seite, jedes Objekt, bereit für Umstrukturierung, Inhaltsänderungen oder Neu-Serialisierung über . Diese Leistung ist das richtige Werkzeug für Seitenmanipulation, denn und brauchen den Baum. Die Kosten sind proportional zum Dokument, nicht zu Ihrer Operation: Die Parsezeit skaliert mit der Objektanzahl, und residenter Speicher läuft auf ein Mehrfaches der Dateigröße hinaus, sobald Objektstrukturen und decodierte Streams berücksichtigt sind
Der Widerspruch zeigt sich, wenn Eingabegrößen unbegrenzt sind. Kunden-Uploads, Scanner-Ausgaben und jahrzehntealte Archive respektieren die Annahmen eines Testkorpus nicht. Eine Pipeline, die jede Eingabe lädt, hat Speicheranforderungen, die von der größten Datei bestimmt werden, die je jemand einreicht. Eine Pipeline, die handlebasierte Lesezugriffe für die Fragen verwendet, bei denen das möglich ist, hat ungefähr konstante Speicheranforderungen. Für einen langlebigen Dienst ist dieser Unterschied wichtiger als rohe Geschwindigkeit
Der Wechsel auf 64 Bit hebt die Grenze an, ändert aber nicht die Ökonomie: Ein Worker, der eine Datei im Gigabytebereich parst, verbraucht weiterhin Sekunden CPU und ein Mehrfaches der Datei im RAM, um Fragen zu beantworten, die die Dateistruktur direkt beantworten könnte. Parallelität verschärft es. Vier gleichzeitige große Ladevorgänge konkurrieren um dasselbe Speicherbudget, sodass der Durchsatz genau dann einbricht, wenn die Warteschlange am vollsten ist
Handlebasierte Inspektion
Die Read-only-Ebene öffnet die Datei als Handle, beantwortet strukturelle Fragen und schließt sie wieder, ohne Objektbaum, ohne Seitenrendering, ohne proportionalen Speicher
var
Pdf: THotPDF;
Handle, PageCount: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Handle := Pdf.DAOpenFileReadOnly('archive-2026-06.pdf', '');
if Handle > 0 then
try
PageCount := Pdf.DAGetPageCount(Handle);
RouteByPageCount('archive-2026-06.pdf', PageCount);
finally
Pdf.DACloseFile(Handle);
end;
finally
Pdf.Free;
end;
end;
Drei Regeln halten diese Ebene zuverlässig. Prüfen Sie das Handle: Ein nicht positiver Rückgabewert bedeutet, dass das Öffnen fehlgeschlagen ist, und ein Aufruf von gegen ein totes Handle ist genau der Fehler, der erst bei der fehlerhaften Kundendatei sichtbar wird. Paaren Sie jedes erfolgreiche Öffnen mit in einem -Block, denn ein Dienst, der Handles verliert, degradiert langsam statt sichtbar zu scheitern. Und kennen Sie die Kosten des Passwortparameters: akzeptiert ein Passwort, fällt bei verschlüsselten Eingaben intern aber auf einen vollständigen Parse zurück, um die Seitenzahl zu beantworten. Die Flat-Memory-Eigenschaft gilt nur für unverschlüsselte Dateien, daher sollten geschützte Eingaben zuerst durch laufen
Die Handle-Ebene eignet sich auch als günstiges Triage-Gate. Dateien kommen von Kunden falsch benannt an, durch fehlgeschlagene Uploads abgeschnitten oder aus anderen Formaten umbenannt. Eine -Probe weist sie in Millisekunden an der Eingangstür zurück, mit einem klaren Fehler an der richtigen Datei, statt sie tief in einem Queue-Worker scheitern zu lassen, wo die Diagnose einen Nachmittag kostet
Whole-file-Operationen: kopieren, entschlüsseln, verschlüsseln
Die zweite Ebene transformiert vollständige Dateien, ohne ihre Interna offenzulegen, und bildet die Arbeitspferde von Intake-Pipelines
// Structural copy: validate-and-move without parsing the object tree
Status := Pdf.DACopyFile('incoming\statement.pdf', 'verified\statement.pdf');
LogDirectFileStatus('copy', Status);
// Decrypt while copying: the Direct File route into protected inputs
Status := Pdf.DecryptFile('incoming\protected.pdf',
'verified\plain.pdf', 'batch-password');
LogDirectFileStatus('decrypt-copy', Status);
// Encrypt while copying: protect an output without a full load
Status := Pdf.EncryptFile('verified\statement.pdf',
'outbound\statement.pdf', 'owner-secret', '', aes256, [prPrint]);
LogDirectFileStatus('encrypt-copy', Status);
Jeder Aufruf hat eine eigene Rolle. ist die validierte Kopie aus einem Quarantäneverzeichnis in verwalteten Speicher. Der Aufruf öffnet und indiziert die PDF-Struktur während des Kopierens, sodass eine abgeschnittene oder Nicht-PDF-Eingabe hier fehlschlägt und nicht drei Stufen später. erzeugt eine entschlüsselte Kopie über einen direkten AES-256-Rewrite-Pfad, der den Aufbau des Objektbaums vermeidet, soweit die Eingabe das zulässt. Es ist das Large-file-Gegenstück zum Load-and-resave-Entschlüsselungsfluss, den der AES-256-Verschlüsselungsartikel beschreibt. ist das Spiegelbild: Passwortschutz wird während einer Kopie auf Dateiebene angewendet, mit denselben Key-Type- und Berechtigungsparametern wie im In-memory-Pfad
Änderungen anhängen statt neu schreiben
Das in ISO 32000-1 §7.5.6 definierte inkrementelle Update ist die dritte Ebene: Die ursprünglichen Bytes bleiben auf dem Datenträger unverändert, und geänderte oder neue Objekte werden danach mit einem Cross-Reference-Abschnitt angehängt, der auf den ursprünglichen zurückkettet. Für ein 900-MB-Archiv, das eine hinzugefügte Seite braucht, sind die Schreibkosten das Delta, nicht die Datei
// Append an audit page to a large archive without rewriting it
Pdf.BeginIncrementalUpdate('archive-2026-06.pdf');
Pdf.AddPage;
Pdf.CurrentPage.SetFont('Arial', [], 10);
Pdf.CurrentPage.TextOut(50, 760, 0, 'Processed by intake service 2026-06-11');
Pdf.SaveIncrementalUpdate('archive-2026-06-stamped.pdf'); // original bytes + delta
Die Disziplin hier: muss auf die Originaldatei zeigen, weil die angehängten Cross-Reference-Daten auf Offsets in ihr zurückverweisen. Und das Modell ist konstruktiv append-only. Jede inkrementelle Speicherung macht die Datei größer, nie kleiner, sodass ein Dokument, das jede Nacht gestempelt wird, unbegrenzt wächst, bis eine periodische Neu-Serialisierung, also Laden des Dokuments und Zurückschreiben über , es kompaktiert. Die Append-only-Eigenschaft macht das inkrementelle Update außerdem zum einzigen sicheren Weg, digital signierte Dokumente zu ändern, eine Einschränkung, die der Artikel über digitale Signaturen und PAdES untersucht; die zugrunde liegende Cross-Reference-Mechanik behandelt der Artikel über Objektstreams und inkrementelle Updates
Eine Eigenschaft von Append-only-Speicherungen wird in Reviews leicht übersehen: Die ursprünglichen Bytes bleiben in der Datei und sind für jeden lesbar, der hinsieht. Ein inkrementelles Update, das eine Seite „ersetzt“, löscht die alte nicht. Es übersteuert sie in der aktuellen Revision, während die vorherige Revision wiederherstellbar bleibt. Verwenden Sie inkrementelle Updates nie, um sensible Inhalte zu entfernen; eine vollständige Neu-Serialisierung, gefolgt von , die nur den aktuellen Zustand trägt, ist der richtige Weg, um Historie abzulegen, die ein Empfänger nicht sehen darf
Die passende Ebene zur Operation wählen
Die Auswahllogik lässt sich auf vier Zeilen verdichten, und es lohnt sich, sie als explizite Routingentscheidung am Anfang einer Pipeline zu codieren, statt jeden Job seinen eigenen Pfad wählen zu lassen:
- Zählen, inspizieren, klassifizieren — ein Handle öffnen: , ,
- Ganze Dateien verschieben, entschlüsseln oder verschlüsseln — Aufrufe auf Dateiebene: , ,
- Seiten umstrukturieren oder Dokumente zusammenführen — vollständig laden: , dann oder , danach
- Ein kleines Delta zu einer großen oder signierten Datei hinzufügen — und speichern
Gemischte Pipelines profitieren von einem Größenschwellwert vor dem Full-load-Pfad: Leiten Sie alles oberhalb einiger hundert Megabyte durch die Direct-File-Ebenen und stellen Sie echte Umstrukturierungsarbeit einem 64-Bit-Worker mit Speicherbudget in die Warteschlange. Der Schwellwert macht aus Out-of-memory-Abstürzen eine explizite, beobachtbare Routingentscheidung
Welche Ebene einen Job auch verarbeitet: Schreiben Sie die Ausgabe zuerst unter einen temporären Namen und benennen Sie sie erst nach erfolgreicher Validierung an den Zielort um. Eine halb geschriebene Datei unter dem endgültigen Namen ist für die nächste Pipeline-Stufe nicht von einer guten zu unterscheiden. Die Direct-File-Aufrufe machen diese Validierung günstig, weil die Bestätigung der Ausgabe selbst eine Ein-Zeilen-Handle-Probe ist
Die Bereitstellung dieser direkten Dateioperation-APIs erfolgt zusammen mit der HotPDF-Komponente für Delphi und C++Builder, als Teil des freigegebenen Begleitpakets. Auf der Homepage der Produktvorstellung ist ein großes Verzeichnis aller Funktionen zur Suche verfügbar; hier können auch die oben genannten zusätzlichen Aufrufparameter nachgeschlagen werden