Kahden gigatavun PDF:n yhdistäminen tai jakaminen ilmeisellä tavalla maksaa sinulle kaksi asiaa kerralla: seinäkeloaikaa ja osoitetilaa. Ilmeinen tapa on ladata kukin syöte, tehdä työ, kirjoittaa tuloste. Lataaminen on missä se rikkoutuu. Skanniava arkisto joka siirtyy 300:sta 600 DPI:hin kaksinkertaistaa lineaarisen resoluutionsa ja likimain nelinkertaistaa levllä, joten sama kokoonpanotyö, joka hoiti 400 MB tiedostoja koko vuoden, alkaa trashaamaan heti kun syöte ylittää gigatavun, usein tekemättä muuta kuin sivujen laskemista. Työ ei koskaan tullut vaikeammaksi. Avaa, laske, valitse välit, ketjuta on koko se. Koko puun lataaminen yksinkertaisesti lakkasi olemasta järkevä oletus tuossa koossa. PDF Library for Delphi, losLabin PDF-kirjasto Delphille ja C++Builderille, vastaa tähän Direct Access -kerroksellaan: perhe DA-etuliitellä varustettuja funktioita, joiden takana on suoratoistolukija, joka kävelee ristiviittaustaulukon paikallaan ennemmin kuin rakentaa koko dokumentin muistiin
Minne muisti menee täyssuoritusLatauksessa
PDF:n "normaali" lataaminen tarkoittaa xref:n jäsentämistä, joka epäsuora objekti resolvoidaan muistissa olevaksi puuksi, objektivirtojen dekoodaamista, ja sivupuun, fonttien ja merkintöjen kytkemistä objekteiksi joita voit muokata. Editointivuokia varten tuo on oikea vaihto. Yhdistämis-, jakamis- ja tarkastustyölle se on enimmäkseen hävikkiä. 30 000-sivuinen skannausarkisto voi pitää sisällään miljoonia epäsuoria objekteja, ja jakotyö tarvitsee lukea muutama sataa niistä: pyydetyn välin sivusolmut, plus mitä nuo solmut viittaavat
Direct Access -kerros kääntää mallin päinvastaiseksi. DAOpenFile ja DAOpenFileReadOnly jäsentävät trailerin ja xref:n, muutaman kilotavun tiedoston hännässä, ja palauttavat tiedostokahvan. Objektit haetaan laiskasti kun kutsu niitä tarvitsee. Käytännön seuraus on, että usean gigatavun tiedoston avaaminen kestää suunnilleen yhtä kauan kuin pienen avaaminen, ja muisti seuraa sitä mitä kosketat ennemmin kuin sitä mitä tiedosto sisältää
Valtavan tiedoston tutkiminen lataamatta
Alla oleva malli tulee kirjaston omasta suurtiedosto-benchmarkista: avaa vain luku -tilassa, kysy kysymyksiä, sulje. Dokumenttipuuta ei koskaan ole olemassa
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;
Vain luku -tila on suositeltavaa aina kun voit: se antaa sisäänoton vaiheen ajaa silloin kun muut prosessit pitävät tiedostoa, ja se dokumentoi tarkoituksen. Tutkintavaihe, joka vahingossa kutsuu mutatoivaa funktiota, epäonnistuu nopeasti ennemmin kuin korruptoi arkiston
PageRef on objektikahva, ei sivunumero
Yksittäisin yleisin DA-API-virhe on sivunumeron välittäminen sinne missä funktio odottaa PageRef:iä. Lähes jokainen per-sivu-DA-kutsu ottaa viitekahvan sivuobjektiin ennemmin kuin sivunumeron: DAExtractPageText, DARenderPageToFile, DARotatePage ja DACapturePage kaikki odottavat viitettä. Saat yhden kääntämällä ihmiskohtaisen numeron DAFindPage:n kautta:
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;
Raon numeron 250 välittäminen sen sijaan ei nosta virhettä. Se osoittaa mihin tahansa objektiin, joka sattuu istumaan tuon kahva-arvon takana, mikä hyvänä päivänä epäonnistuu näkyvästi ja huonona päivänä poimii tekstin väärältä sivulta asiakaskohtaiseen dokumenttiin. Jos käärit DA-kerroksen omaan palvelukoodiisi, tee käännös mahdottomaksi ohittaa: ota sivunumerot rajalla, kutsu DAFindPage:ä heti, ja välitä vain viitteitä sisäisesti
Satojen tiedostojen yhdistäminen nimetyllä listalla
Kahdelle tiedostolle MergeFiles(First, Second, Output) riittää. Eräkokoonpano skaalautuu paremmin tiedostolistojen kautta: rekisteröi syötteet listanimen alle, sitten yhdistä lista yhdessä läpikäynnissä
Lib.AddToFileList('Statements', 'jan.pdf');
Lib.AddToFileList('Statements', 'feb.pdf');
Lib.AddToFileList('Statements', 'mar.pdf');
Lib.MergeFileList('Statements', 'q1-statements.pdf');
// Varmista tulos halvalla tavalla: suora käyttö uudelleen
Handle := Lib.DAOpenFileReadOnly('q1-statements.pdf', '');
Writeln('merged pages: ', Lib.DAGetPageCount(Handle));
Lib.DACloseFile(Handle);
Yhdistämisperheellä on kolme varianttia, ja ero ei ole yksin nopeus. MergeFileListFast ohittaa rakennepuun säilyttämisen; MergeFileListStrict pakottaa tiukan tilan; suffikiton versio on tasapainoinen oletus. Käytäntösääntö joka putoaa: jos yksikään syöte on Tagged PDF, jonka saavutettavuusrakenne on säilytettävä, PDF/UA:ta varten tuotettu olkoon ilmeinen tapaus, tavoittele oletusta tai tiukkaa varianttia, koska Fast hiljaa pudottaa rakennepuun. Pelkille skannausarkistoille ilman tagitusta, Fast on ilmaista suorituskykyä. Päätä per putki, ei per kehittäjän mieliala, ja tallenna käytetty variantti työlokiin
Jakaminen lataamatta: välien poiminta
Jakaminen noudattaa samaa ei-lataus-filosofiaa. ExtractFilePages(InputFileName, Password, OutputFileName, RangeList) vetää sivuvälin suoraan tiedostosta tiedostoon, väililuettelolla kuten '1-500', '501-1000', tai pilkuilla erotetuilla valinnoilla, ja lähde ei koskaan tule dokumenttipuuksi. Kun dokumentti on jo ladattu muista syistä, ExtractPageRanges tuottaa uuden muistissa olevan dokumentin nykyisestä, ja CopyPageRanges vetää välejä toisesta ladatusta dokumentista ID:n perusteella. Per-lasku-jako yhdistetyistä tulostusvirroista, tiedostosta-tiedostoon-muoto on se, joka pitää 4 GB syötteen koskaan turpoamasta RAM:iin
Tiedostot, jotka valehtelevat geometriastaan
Suurtiedostoputket kohtaavat vaurioituneita tiedostoja tahtiin, joita pientiedostoputket eivät koskaan näe, yksinkertaisesti koska syötteet kulkevat useampien järjestelmien läpi. Kaksi vikamuotoa ansaitsevat eksplisiittisen käsittelyn
Ensinnä, siirtyneet otsikot. Sähköpostiyhdyskäytävät ja tulostuserottimet joskus prependoivat tavuja PDF:ään, joten %PDF-merkki ei enää istu offsetissa 0 ja jokainen xref-offset tiedostossa on väärin samalla määrällä. Suoratoistolukija havaitsee tämän ja paljastaa sen (DAShiftedHeader flat-tasolla, ShiftedHeader TSmartPDFReader:llä), sitten kompensoi sitä luvuissa. Kotikasvatuset offset-aritmetiikka tyypillisesti ei, mistä syystä "toimii jokaisessa tiedostossa jonka tuotamme, epäonnistuu asiakas X:n tiedostoissa" on klassinen oire
Toiseksi, rikki olevat ristiviittaustaulukot. DACopyFile(InputFileName, OutputFileName, PageCount) suoratoistaa koko tiedoston uuteen kopioon samalla kun rakentaa xref:iä uudelleen, palauttaen sivumäärän sivutuotteena. Sen ajaminen normalisointivaiheena vaativan alavirran kuluttajan edessä muuttaa luokan ajoittaisia parse-epäonnistumisia yhdeksi ennustettavaksi korjausvaiheeksi. Ja kun omat muokkauksesi tarvitsevat tallennusta, DAAppendFile kirjoittaa ne inkrementaalipäivityksenä, liittäen uuden version ennemmin kuin uudelleenkirjoittaen gigatavuja, mikä pitää tallennuskustannuksen suhteessa muutokseen ennemmin kuin tiedostoon
Toimitusyksityiskohdat: linearisointi ja kompositio
Kaksi vierekkäistä kykyä täydentävät suurtiedostoputken. Kun koottu tuloste tarjoillaan HTTP:n yli selaimessa katselua varten, LinearizeFile järjestää sen uudelleen tavuväli-suoratoistoa varten, jolloin ensimmäinen sivu näkyy ennen kuin loput 500 MB paketista on ladattu. Aja se viimeisenä vaiheena, kaiken yhdistämisen jälkeen, koska mikä tahansa myöhempi muutos de-linearisoi tiedoston uudelleen. Ja kun paketit tarvitsevat kompositiota ennemmin kuin pelkkää ketjutusta, sano kansisivu joka leimataan jokaisen laskun taakse tai kaksi lähdesivua jotka asetetaan yhdelle tulostesivulle, DACapturePage muuttaa minkä tahansa sivun uudelleenkäytettäväksi mallipohjaksi, jonka DADrawCapturedPage asettaa kohdesivulle mielivaltaiseen suorakulmioon, yhä ilman täyttä dokumenttilatausta usean gigatavun lähteelle
Rajat ja mikä pysyy vain luku -tilassa
Formaatti itse loppuu tilaa pitkään ennen Direct Accessia. Offsetit ovat Int64 koko matkan DA-kerroksen läpi, joten todelliset katot ovat käytettävissä oleva levy ja klassisten (ei-virta) ristiviittaustaulukoiden 10-numeroinen xref-offset-kenttä. Usean gigatavun skannausarkistot ovat käytännössä tavallisia, ja muisti pysyy rajattuna tiedostokoosta riippumatta koska objekteja luetaan vain kun kutsu niitä pyytää
Kaksi kysymystä nousee tarpeeksi usein vastattavaksi suoraan. Yhdistäminen oletuspolun kautta kantaa dokumenttirakenteen yli, joten kirjanmerkit ja linkit säilyvät; Fast-variantti on se, joka vaihtaa rakennepuun nopeuteen, mikä on koko syy reserveerata se tagittomille syötteille. Turvallinen tapa on avata yhdistetty tuloste, kävellä sen ääriviivat, ja tarkistaa muutama sisäinen linkki ennen toimitusta. Mitä tulee editointiin: on hyödyllinen välimaasto vain-luku-tutkimisen ja täyslatauksen välillä. Sivutason operaatiot toimivat kahvalla suoraan, DARotatePage, DAMovePage ja DAHidePage niiden joukossa, sekä lomakekenttäluvut, ja DAAppendFile pysäyttää nuo muokkaukset inkrementaaliversiona. Sisältötason editointi, mikä tahansa joka uudelleenkirjoittaa merkintäoperaattorit sivun sisällä, kuuluu yhä täydelle dokumenttikerrokselle
Liittyvät artikkelit
Jos yhdistetyn tulosteesi on pysyttävä saavutettavana, rakennepuun taustaa on käsitelty Tagged PDF -saavutettavuusartikkelissa, joka selittää tarkalleen mitä Fast-yhdistämisvariantti heittäisi pois. Sisällön vetämiseksi ulos väleistä, joita jaat, katso tekstin, kuvien ja fonttien poimintaopastus
Täydellinen Direct Access -funktioluettelo toimitetaan kirjaston mukana; editiot ja kokeiluversioiden lataukset löytyvät PDF Library for Delphi -tuotesivulta