Egy 1,4 GB-os beolvasott archívum oldalainak megszámolása olcsó kellene, hogy legyen. Hívja meg a LoadFromFile metódust ezen a fájlon, és megszűnik olcsónak lenni: a HotPDF elemzi a kereszthivatkozási adatokat, és memóriabeli objektumot épít a dokumentum több százezer közvetett objektumának mindegyikéhez, egy 32 bites feldolgozó pedig valahol ennek az elemzésnek a közepén ütközik a 2 GB-os címtérplafonba. Az a művelet, amelyet valójában akart — az oldalszám —, ezekből az objektumokból egyet sem igényelt. Az oldalfára volt szüksége, semmi másra. Ez a rés, aközött, amit egy feladat kér, és amit a teljes betöltés ad, a Direct File API teljes létjogosultsága
A Direct File API fájlszintű hozzáférést ad a Delphi és C++Builder kódnak egy PDF-hez: oldalszámot, másolást, visszafejtést, növekményes hozzáfűzést, és mindegyik azt olvassa be a lemezről, amire valóban szüksége van, ahelyett hogy a teljes dokumentummodellt újraépítené a memóriában. A készség abban áll, hogy minden feladatot a legkönnyebb olyan szinthez rendel, amely még meg tudja válaszolni. Ha ez az illesztés jó, a szolgáltatás memóriaigénye bármekkora bemenetnél lapos marad. Ha rossz, az első túlméretezett fájl leviszi a feldolgozót
Mibe kerül egy teljes betöltés?
A LoadFromFile nem az ellenség. Megszolgálja a memóriáját: ha a fa a RAM-ban van, közvetlen hozzáférése van minden oldalhoz és minden objektumhoz, és pontosan ezt kívánja az InsertPagesFromDocument, a MovePage és a SaveLoadedDocument hívással történő újbóli sorosítás. Valódi átszerkesztéshez nincs rövidebb út; ahhoz kézben kell tartani a dokumentumot, hogy átrendezze
A baj akkor kezdődik, amikor a bemeneti méretek nem az Ön kezében vannak. Az ügyfélfeltöltések, a lapolvasók kimenete és az évtizeddel ezelőtti archívumok fütyülnek arra, amit a tesztkorpusza feltételezett. Töltsön be minden bemenetet feltétel nélkül, és a memóriaplafonját az az egyetlen legnagyobb fájl szabja meg, amelyet valaha bárki beküld. Az elemzési idő az objektumszámot követi, a rezidens memória pedig az objektumszerkezetek és a dekódolt folyamok beszámítása után a fájlméret többszörösén állapodik meg, tehát egy gigabájt a lemezen több gigabájtot jelenthet a memóriában
A 64 bitre való újrafordítás megemeli a címtérplafont, de a számlát érintetlenül hagyja. A feldolgozó továbbra is másodperceket éget a processzoron és a fájl többszörösét a RAM-ban, hogy megválaszoljon egy kérdést, amelyet a fájl saját szerkezete ezredmásodpercek alatt megválaszolhatott volna. Egyidejűség mellett a matematika ellenségessé válik: négy nagy betöltés egyszerre osztozik egy memóriakereten, és az áteresztés pontosan akkor omlik be, amikor a sor a legmélyebb, és ezt engedheti meg magának a legkevésbé
Fájl olvasása leírón át
A csak olvasható szint leíróként nyit meg egy fájlt, megválaszolja a szerkezetéről szóló kérdéseket, majd bezárja. Nincs objektumfa, nincs oldalrajzolás, nincs olyan memória, amely a bemenettel együtt nő
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;
Három szokás tartja becsületesen ezt a szintet. Először: ellenőrizze a visszatérési értéket. A nem pozitív leíró sikertelen megnyitást jelent, és a DAGetPageCount elsütése egy halott leírón az a fajta hiba, amely addig marad rejtve, amíg egy ügyfél hibás felépítésű fájlt nem küld. Másodszor: minden sikeres megnyitáshoz párosítson DACloseFile hívást egy finally blokkban; az a szolgáltatás, amely leírókat szivárogtat, nem összeomlik, hanem lassan rothad, ami rosszabb. Harmadszor: tartsa tiszteletben, mit csinál valójában a jelszóparaméter. A DAOpenFileReadOnly elfogad egyet, de titkosított bemeneteknél csendben teljes elemzésre esik vissza, hogy kiolvassa az oldalszámot, így a lapos memória garanciája elpárolog. Terelje előbb a DecryptFile hívásra a védett fájlokat, és a munkafolyamat többi része olcsó marad
Ugyanez a vizsgálat válogatókapuként is szolgál. A fájlok tévesen címkézve, félig feltöltve vagy valamilyen egészen más formátumból átnevezve bukkannak fel, és egy DAOpenFileReadOnly ellenőrzés mindezt ezredmásodpercek alatt visszautasítja már a bejáratnál, a hibát pedig a vétkes fájlhoz szögezi. Ennek alternatívája az, hogy egy szemétfájl mélyen befut egy sorkezelő feldolgozóba, és ott robban fel, ahol egy délutánba kerülhet kibogozni, melyik bemenet okozta
Teljes fájlok másolása, visszafejtése és titkosítása
A második szint teljes fájlokat mozgat és alakít át anélkül, hogy valaha kitenné a belsejüket. Ezekre a hívásokra támaszkodnak leginkább a beolvasási munkafolyamatok
// Szerkezeti másolás: ellenőrzés és áthelyezés az objektumfa elemzése nélkül
Status := Pdf.DACopyFile('incoming\statement.pdf', 'verified\statement.pdf');
LogDirectFileStatus('copy', Status);
// Visszafejtés másolás közben: a Direct File út a védett bemenetekhez
Status := Pdf.DecryptFile('incoming\protected.pdf',
'verified\plain.pdf', 'batch-password');
LogDirectFileStatus('decrypt-copy', Status);
// Titkosítás másolás közben: kimenet védelme teljes betöltés nélkül
Status := Pdf.EncryptFile('verified\statement.pdf',
'outbound\statement.pdf', 'owner-secret', '', aes256, [prPrint]);
LogDirectFileStatus('encrypt-copy', Status);
Mindegyik hívás megszolgálja a helyét. A DACopyFile az ellenőrzött másolás egy karanténkönyvtárból a kezelt tárolóba: menet közben megnyitja és indexeli a PDF szerkezetét, tehát egy csonka vagy nem PDF bemenet már itt elhasal, nem három szakasszal lejjebb. A DecryptFile visszafejtett másolatot ír egy közvetlen AES-256 újraírási úton, amely kihagyja az objektumfát, valahányszor a bemenet ezt megengedi — ez a nagy fájlokra szabott párja annak a betöltéses-újramentéses visszafejtési folyamatnak, amelyet az AES-256 titkosításról szóló cikk tárgyal. Az EncryptFile ugyanezt a mozdulatot fordítva végzi: fájlszintű másolás közben alkalmaz jelszavas védelmet ugyanazokkal a kulcstípus- és jogosultságparaméterekkel, amelyeket a memóriabeli út is használ
Változások hozzáfűzése újraírás helyett
A növekményes frissítés, amelyet az ISO 32000-1 §7.5.6 határoz meg, a harmadik szint. Az eredeti bájtok ott maradnak a lemezen, ahol voltak, az új vagy módosított objektumok pedig utánuk fűződnek, majd egy friss kereszthivatkozási szakasz következik, amely visszaláncolódik az eredetibe. Egy 900 MB-os archívumnál, amelyhez egyetlen oldalt kell hozzáadni, az írás költsége a különbözet, nem a teljes fájl
// Ellenőrzési oldal hozzáfűzése egy nagy archívumhoz annak újraírása nélkül
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'); // eredeti bájtok + különbözet
Itt két fegyelmi pont számít. A BeginIncrementalUpdate hívásnak az eredeti fájlra kell mutatnia, mert a hozzáfűzött kereszthivatkozási adatok az azon belüli bájteltolásokra láncolódnak vissza. A modell pedig tervezésénél fogva csak hozzáfűz: minden növekményes mentés növeli a fájlt, soha nem zsugorítja. Az éjszakánként bélyegzett dokumentum korlátlanul hízik, amíg egy időszakos újrasorosítás — betöltés, majd visszaírás a SaveLoadedDocument hívással — össze nem tömöríti. Ugyanez a csak hozzáfűző természet teszi a növekményes frissítést az egyetlen biztonságos móddá arra, hogy digitálisan aláírt dokumentumhoz nyúljon, és ezt a megkötést a digitális aláírásokról és a PAdES szabványról szóló cikk vizsgálja. Az alatta lévő kereszthivatkozási gépezet külön tárgyalást kap az objektumfolyamokról és a növekményes frissítésekről szóló cikkben
A csak hozzáfűző mentésekben van egy csapda, amely a legtöbb átnézésen átcsúszik. Az eredeti bájtok a fájlban maradnak, olvashatóan bárki számára, aki hajlandó megnézni. Az a növekményes frissítés, amely „lecserél” egy oldalt, nem törli a régit; csak felülírja az aktuális revízióban, miközben a korábbi revízió ott ül, teljesen visszanyerhetően. A növekményes frissítés tehát rossz eszköz érzékeny tartalom eltávolítására. Ha valóban el akar dobni olyan előzményt, amelyet a címzettnek soha nem szabad látnia, teljes újrasorosításra van szüksége: LoadFromFile, majd SaveLoadedDocument, amely csak az aktuális állapotot írja ki, és otthagyja az eltemetett revíziókat
A szint illesztése a művelethez
A választási logika elég rövid ahhoz, hogy fejben tartsa, és megéri kifejezett irányítási döntésként rögzíteni a munkafolyamat elején ahelyett, hogy minden feladat a saját útját rögtönözné. A szükséges művelet dönti el a szintet:
- Számolás, vizsgálat vagy besorolás leírót nyit:
DAOpenFileReadOnly,DAGetPageCount,DACloseFile - Teljes fájl mozgatása, visszafejtése vagy titkosítása fájlszinten marad a
DACopyFile, aDecryptFilevagy azEncryptFilehívással - Oldalak átszerkesztése vagy dokumentumok egyesítése teljes betöltést kíván:
LoadFromFile, majdInsertPagesFromDocumentvagyMovePage, aztánSaveLoadedDocument - Kis különbözet hozzáadása egy óriási vagy aláírt fájlhoz a
BeginIncrementalUpdatehívást használja, majd ment
A vegyes munkafolyamatok jól teszik, ha méretküszöböt tesznek a teljes betöltés útja elé. Mindent, ami néhány száz megabájt fölött van, terelje a Direct File szintekre, a teljes betöltést pedig tartsa fenn a valódi átszerkesztésre, 64 bites feldolgozón, valós memóriakerettel. A küszöb egy memóriahiányos összeomlást olyan irányítási döntéssé alakít, amelyet lát és hangolni tud
Bármelyik szint kezeli is a feladatot, írja a kimenetét ideiglenes néven, és csak akkor nevezze át a helyére, ha az eredmény érvényesnek bizonyul. A félig megírt fájl a végleges név alatt a munkafolyamat következő szakasza számára pontosan úgy néz ki, mint egy jó, a Direct File hívások pedig olcsóvá teszik az ellenőrzést: egy kimenet igazolása egysoros leírós vizsgálat
A Direct File API a HotPDF Delphi Component részeként érkezik, Delphihez és C++Builderhez. A termékoldal hivatkozik a teljes függvényhivatkozásra, benne az itt bemutatott növekményes frissítési hívásokkal