Een PDF van twee gigabyte samenvoegen of splitsen op de voor de hand liggende manier kost u twee dingen tegelijk: verstreken tijd en adresruimte. De voor de hand liggende manier is elke invoer laden, het werk doen, de uitvoer schrijven. Het laden is waar het breekt. Een scanarchief dat van 300 naar 600 DPI gaat verdubbelt zijn lineaire resolutie en groeit op schijf ruwweg viermaal, dus dezelfde assemblagejob die het hele jaar 400 MB-bestanden afhandelde begint te thrashen zodra een invoer een gigabyte overschrijdt, vaak terwijl hij niet meer doet dan pagina's tellen. De taak werd nooit moeilijker. Openen, tellen, bereiken kiezen, samenvoegen is het hele verhaal. Volledige-boom-laden hield eenvoudig op een zinnige standaard te zijn op die grootte. PDF Library for Delphi, losLab's PDF-bibliotheek voor Delphi en C++Builder, beantwoordt dit met zijn Direct Access-laag: een familie van DA-geprefixte functies ondersteund door een streaming reader die de cross-reference-tabel in-place doorloopt in plaats van het hele document in het geheugen op te bouwen
Waar het geheugen heen gaat bij een volledige lading
Een PDF "normaal" laden betekent de xref parsen, elk indirect object herleiden tot een in-memory boom, objectstreams decoderen, en de paginaboom, lettertypen en annotaties verbinden tot objecten die u kunt manipuleren. Voor bewerkingsworkflows is dat de juiste afweging. Voor samenvoeg-, splits- en inspectiewerk is het grotendeels verspilling. Een scanarchief van 30.000 pagina's kan miljoenen indirecte objecten bevatten, en een splitsjob hoeft er slechts enkele honderden te lezen: de paginaknooppunten in het gevraagde bereik, plus wat die knooppunten refereren
De Direct Access-laag keert het model om. DAOpenFile en DAOpenFileReadOnly parsen de trailer en xref, een paar kilobytes aan het staarteinde van het bestand, en retourneren een bestands-handle. Objecten worden lui opgehaald wanneer een aanroep ze nodig heeft. Het praktische gevolg is dat het openen van een multigigabyte-bestand ongeveer even lang duurt als het openen van een klein bestand, en het geheugen volgt wat u aanraakt in plaats van wat het bestand bevat
Een enorm bestand peilen zonder het te laden
Het patroon hieronder komt uit de eigen large-file-benchmark van de bibliotheek: alleen-lezen openen, vragen stellen, sluiten. Er bestaat nooit een documentboom
var
Lib: TPDFlib;
Handle, Pages: Integer;
begin
Lib := TPDFlib.Create;
try
Handle := Lib.DAOpenFileReadOnly('archive-2025.pdf', '');
if Handle = 0 then
raise Exception.Create('Direct access open failed');
Pages := Lib.DAGetPageCount(Handle);
Writeln('pages : ', Pages);
Writeln('title : ', Lib.DAGetInformation(Handle, 'Title'));
Lib.DACloseFile(Handle);
finally
Lib.Free;
end;
end;
Alleen-lezen-modus is de voorkeur waard wanneer u kunt: het laat de intake-fase draaien terwijl andere processen het bestand vasthouden, en het documenteert intentie. Een probe-fase die per ongeluk een muterende functie aanroept faalt snel in plaats van het archief te corrumperen
PageRef is een object-handle, geen paginanummer
De meest voorkomende fout met de DA-API is een paginanummer doorgeven waar een functie een PageRef verwacht. Bijna elke per-pagina DA-aanroep neemt een referentie-handle naar het paginaobject in plaats van een paginanummer: DAExtractPageText, DARenderPageToFile, DARotatePage en DACapturePage verwachten allemaal een ref. U krijgt er een door het mensgerichte getal te vertalen via DAFindPage:
PageRef := Lib.DAFindPage(Handle, 250); // page number -> object handle
if PageRef <> 0 then
begin
Text := Lib.DAExtractPageText(Handle, PageRef, 0);
Lib.DARenderPageToFile(Handle, PageRef, 5, 150, 'page250.png');
end;
Het ruwe getal 250 doorgeven in plaats daarvan roept geen fout op. Het adresseert welk object dan ook dat toevallig achter die handle-waarde zit, wat op een goede dag zichtbaar faalt en op een slechte dag tekst uit de verkeerde pagina extraheert in een klantgericht document. Als u de DA-laag in uw eigen servicecode verpackt, maak de vertaling dan onmogelijk over te slaan: accepteer paginanummers aan de grens, roep onmiddellijk DAFindPage aan, en geef intern alleen refs door
Honderden bestanden samenvoegen met een benoemde lijst
Voor twee bestanden is MergeFiles(First, Second, Output) voldoende. Batch-assemblage schaalt beter via bestandslijsten: registreer invoeren onder een lijstnaam en voeg de lijst dan in één pas samen
Lib.AddToFileList('Statements', 'jan.pdf');
Lib.AddToFileList('Statements', 'feb.pdf');
Lib.AddToFileList('Statements', 'mar.pdf');
Lib.MergeFileList('Statements', 'q1-statements.pdf');
// Het resultaat goedkoop verifiëren: opnieuw directe toegang
Handle := Lib.DAOpenFileReadOnly('q1-statements.pdf', '');
Writeln('merged pages: ', Lib.DAGetPageCount(Handle));
Lib.DACloseFile(Handle);
De samenvoeg-familie heeft drie varianten, en het verschil is niet alleen snelheid. MergeFileListFast slaat behoud van de structuurboom over; MergeFileListStrict dwingt strict-modus af; de ongevormde versie is het gebalanceerde midden. De operationele regel die daaruit voortkomt: als een invoer een getagde PDF is waarvan de toegankelijkheidsstructuur moet overleven, alles wat voor PDF/UA wordt geproduceerd het voor de hand liggende geval, grijp dan naar de standaard- of Strict-variant, want Fast laat de structuurboom stilletjes vallen. Voor gewone scanarchieven zonder tagging is Fast gratis prestatie. Beslis per pipeline, niet per ontwikkelaarsstemming, en leg de gebruikte variant vast in het job-log
Splitsen zonder laden: bereikextractie
Splitsen volgt dezelfde geen-lading-filosofie. ExtractFilePages(InputFileName, Password, OutputFileName, RangeList) trekt een paginabereik rechtstreeks van bestand naar bestand, met een bereiklijst zoals '1-500', '501-1000' of door komma's gescheiden selecties, en de bron wordt nooit een documentboom. Wanneer een document om andere redenen al is geladen, produceert ExtractPageRanges een nieuw in-memory document uit het huidige, en CopyPageRanges trekt bereiken over vanuit een ander geladen document op ID. Voor per-afschrift-splitsen van geconsolideerde printstreams is de bestand-naar-bestand-vorm degene die voorkomt dat een 4 GB-invoer ooit in RAM opzwelt
Bestanden die liegen over hun geometrie
Large-file-pipelines ontmoeten beschadigde bestanden in een tempo dat small-file-pipelines nooit zien, eenvoudigweg omdat de invoeren door meer systemen gaan. Twee faalvormen verdienen expliciete afhandeling
Ten eerste, verschoven headers. Mail-gateways en print-spoolers prependen soms bytes aan een PDF, zodat de %PDF-marker niet langer op offset 0 staat en elke xref-offset in het bestand met hetzelfde bedrag fout is. De streaming reader detecteert dit en toont het (DAShiftedHeader op het platte niveau, ShiftedHeader op TSmartPDFReader), en compenseert het vervolgens tijdens het lezen. Zelfgebouwde offset-rekenkunde doet dat meestal niet, vandaar dat "werkt op elk bestand dat we genereren, faalt op bestanden van klant X" het klassieke symptoom is
Ten tweede, kapotte cross-reference-tabellen. DACopyFile(InputFileName, OutputFileName, PageCount) streamt het hele bestand naar een nieuwe kopie terwijl de xref wordt herbouwd, en retourneert het paginatotaal als bijproduct. Het uitvoeren ervan als een normalisatiestap vóór een kieskeurige downstream-consument zet een klasse van intermitterende parse-fouten om in één voorspelbare reparatiestap. En wanneer uw eigen bewerkingen opslaan moeten, schrijft DAAppendFile ze als een incrementele update, waarmee een nieuwe revisie wordt toegevoegd in plaats van gigabytes te herschrijven, wat de opslagkosten proportioneel houdt aan de wijziging in plaats van aan het bestand
Leverdetails: linearisatie en compositie
Twee aangrenzende mogelijkheden ronden een large-file-pipeline af. Wanneer de geassembleerde uitvoer over HTTP wordt geserveerd voor weergave in de browser, reorganiseert LinearizeFile die voor byte-range-streaming zodat de eerste pagina toont voordat de rest van een 500 MB-pakket is gedownload. Voer het uit als de laatste fase, na al het samenvoegen, want elke latere wijziging de-lineariseert het bestand weer. En wanneer pakketten compositie nodig hebben in plaats van gewone concatenatie, zeg een omslag die achter elk afschrift wordt gestempeld of twee bronpagina's die op één uitvoerblad worden samengevoegd, maakt DACapturePage van elke pagina een herbruikbaar sjabloon dat DADrawCapturedPage op een bestemmingspagina in een willekeurige rechthoek plaatst, nog steeds zonder een volledige documentlading op de multigigabyte-bron
Limieten en wat alleen-lezen blijft
Het formaat zelf raakt de limiet lang voordat Direct Access dat doet. Offsets zijn Int64 de hele weg door de DA-laag, dus de echte plafonds zijn beschikbare schijfruimte en het 10-cijferige xref-offsetveld van klassieke (non-stream) cross-reference-tabellen. Multigigabyte-scanarchieven zijn in de praktijk onopvallend, en het geheugen blijft gebonden ongeacht de bestandsgrootte omdat objecten alleen worden gelezen wanneer een aanroep erom vraagt
Twee vragen komen vaak genoeg voor om ze direct te beantwoorden. Samenvoegen via het standaardpad draagt documentstructuur over, dus bladwijzers en links overleven; de Fast-variant is degene die de structuurboom voor snelheid inruilt, wat precies de reden is om hem voor ongetagde invoeren te reserveren. De veilige gewoonte is om de samengevoegde uitvoer te openen, de outline ervan te doorlopen en een paar interne links te steekproeven voordat u verzendt. Wat betreft bewerken: er is een nuttig middengebied tussen alleen-lezen-proben en een volledige lading. Paginaniveau-bewerkingen werken rechtstreeks op de handle, DARotatePage, DAMovePage en DAHidePage daaronder, samen met formulierveld-lezingen, en DAAppendFile persisteert die bewerkingen als een incrementele revisie. Inhoudsniveau-bewerken, alles wat de markerings-operatoren binnen een pagina herschrijft, behoort nog steeds tot de volledige documentlaag
Gerelateerde artikelen
Als uw samengevoegde uitvoer toegankelijk moet blijven, wordt de achtergrond van de structuurboom behandeld in het getagde PDF-toegankelijkheidsartikel, dat precies uitlegt wat de Fast-samenvoegvariant zou weggooien. Voor het eruit trekken van inhoud uit de bereiken die u splitst, zie de gids voor tekst-, afbeeldings- en lettertype-extractie
De volledige Direct Access-functielijst wordt meegeleverd met de bibliotheek; edities en trial-downloads staan op de PDF Library for Delphi-productpagina