1,4 GB'lık taranmış bir arşivdeki sayfaları saymak ucuz olmalıdır. Bu dosyada LoadFromFile'ı çağırın ve ucuz olmaktan çıkar: HotPDF, çapraz referans verisini ayrıştırır ve belgenin yüz binlerce dolaylı nesnesinin her biri için bellekte bir nesne oluşturur, 32 bit bir işçi ise bu ayrıştırmanın ortasında bir yerde 2 GB adres alanı tavanına çarpar. İstediğiniz işlem, sayfa sayısı, bu nesnelerin hiçbirine hiç ihtiyaç duymadı. Yalnızca sayfa ağacına ihtiyacı vardı, başka hiçbir şeye değil. Bir işin istediği şey ile tam bir yüklemenin sunduğu şey arasındaki bu boşluk, Direct File API'nin var olmasının tüm nedenidir
Direct File API, Delphi ve C++Builder'a bir PDF'e dosya düzeyinde erişim verir: sayfa sayıları, kopyalar, şifre çözme, artımlı ekler, hepsi tüm belge modelini RAM'de yeniden oluşturmak yerine diskten gerçekte neye ihtiyaç duyduklarını okur. Beceri, her işi onu yanıtlayabilecek en hafif katmanla eşleştirmektir. Bu eşleşmeyi doğru yapın ve bir servis herhangi bir girdi boyutunda düz belleği korur. Yanlış yapın ve ilk aşırı büyük dosya işçiyi devre dışı bırakır
Tam bir yüklemenin size maliyeti
LoadFromFile düşman değildir. Belleğini hak eder: ağaç RAM'de olduğunda her sayfaya ve her nesneye rastgele erişiminiz olur, ki bu tam olarak InsertPagesFromDocument, MovePage ve SaveLoadedDocument üzerinden yeniden serileştirmenin gerektirdiği şeydir. Gerçek yeniden yapılandırma için bir kısayol yoktur; onu yeniden düzenlemek için belgeyi elinizde tutmanız gerekir
Sorun, girdi boyutlarının sizin kontrolünüzde olmadığı zaman başlar. Müşteri yüklemeleri, tarayıcı çıktısı ve on yıl önceki arşivler, test belge kümenizin varsaydığı her şeyi görmezden gelir. Her girdiyi koşulsuz olarak yükleyin, bellek tavanınız herhangi birinin göndereceği en büyük tek dosya tarafından belirlenir. Ayrıştırma süresi nesne sayısını izler ve yerleşik bellek, nesne yapıları ve çözülmüş akışlar sayıldıktan sonra dosya boyutunun birkaç katına yerleşir, bu yüzden diskteki bir gigabayt, yerleşikte birkaç gigabayt anlamına gelebilir
64 bit için yeniden derlemek adres alanı tavanını kaldırır ama faturayı olduğu gibi bırakır. İşçi hâlâ, dosyanın kendi yapısının milisaniyelerde yanıtlayabileceği bir soruyu yanıtlamak için saniyelerce CPU ve dosyanın birkaç katı RAM harcar. Eşzamanlılık altında matematik düşmanlaşır: aynı anda çalışan dört büyük yükleme tek bir bellek bütçesini paylaşır ve verim, kuyruk en derin olduğu ve buna en az gücünüzün yettiği anda tam olarak çöker
Bir dosyayı bir tutamaç üzerinden okumak
Salt okunur katman, bir dosyayı tutamaç olarak açar, onunla ilgili yapısal soruları yanıtlar ve kapatır. Nesne ağacı yok, sayfa render'ı yok, girdiyle birlikte büyüyen bellek yok
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;
Üç alışkanlık bu katmanı dürüst tutar. Birincisi, dönüş değerini kontrol edin. Pozitif olmayan bir tutamaç, açılışın başarısız olduğu anlamına gelir ve ölü bir tutamaca DAGetPageCount ateşlemek, bir müşteri bozuk bir dosya gönderene kadar gizli kalan türden bir hatadır. İkincisi, her başarılı açılışı bir finally bloğu içinde DACloseFile ile eşleştirin; tutamaç sızdıran bir servis çökmez, yalnızca çürür, ki bu daha kötüdür. Üçüncüsü, parola parametresinin gerçekte ne yaptığına saygı gösterin. DAOpenFileReadOnly bir tane kabul eder, ancak şifreli girdiler için sayfa sayısını okumak amacıyla sessizce tam bir ayrıştırmaya düşer, bu yüzden düz-bellek garantisi buharlaşır. Korunan dosyaları önce DecryptFile'dan geçirin, hattın geri kalanı ucuz kalır
Aynı yoklama bir triyaj kapısı olarak da işlev görür. Dosyalar yanlış etiketlenmiş, yarım yüklenmiş ya da tamamen başka bir biçimden yeniden adlandırılmış olarak ortaya çıkar ve bir DAOpenFileReadOnly kontrolü, bunların hepsini ön kapıda milisaniyeler içinde reddeder, hata suçlu dosyaya sabitlenmiş olarak. Alternatif, bir çöp dosyanın bir kuyruk işçisine derinlemesine binmesine ve orada patlamasına izin vermektir, ki hangi girdinin buna neden olduğunu çözmek bir öğleden sonraya mal olabilir
Tüm dosyaları kopyalamak, şifresini çözmek ve şifrelemek
İkinci katman, dosyaları içlerini hiç açığa çıkarmadan tam olarak taşır ve dönüştürür. Bunlar alım hatlarının en çok dayandığı çağrılardır
// Yapısal kopya: nesne ağacını ayrıştırmadan doğrula-ve-taşı
Status := Pdf.DACopyFile('incoming\statement.pdf', 'verified\statement.pdf');
LogDirectFileStatus('copy', Status);
// Kopyalarken şifresini çöz: korunan girdilere Direct File yolu
Status := Pdf.DecryptFile('incoming\protected.pdf',
'verified\plain.pdf', 'batch-password');
LogDirectFileStatus('decrypt-copy', Status);
// Kopyalarken şifrele: tam bir yükleme olmadan bir çıktıyı koru
Status := Pdf.EncryptFile('verified\statement.pdf',
'outbound\statement.pdf', 'owner-secret', '', aes256, [prPrint]);
LogDirectFileStatus('encrypt-copy', Status);
Her çağrı yerini hak eder. DACopyFile, bir karantina dizininden yönetilen depolamaya doğrulanmış kopyadır: PDF yapısını ilerledikçe açar ve indeksler, bu yüzden kesilmiş ya da PDF olmayan bir girdi üç aşama aşağı akışta değil, tam burada başarısız olur. DecryptFile, girdi izin verdiğinde nesne ağacını atlayan doğrudan bir AES-256 yeniden yazma yolu boyunca şifresi çözülmüş bir kopya yazar, AES-256 şifreleme makalesinde ele alınan yükle-ve-yeniden-kaydet şifre çözme akışının büyük dosya karşılığı. EncryptFile, aynı hareketi tersine çalıştırır, bellek içi yolun zaten kullandığı anahtar türü ve izin parametreleriyle dosya düzeyinde bir kopyalama sırasında parola koruması uygular
Yeniden yazmak yerine değişiklikleri eklemek
ISO 32000-1 §7.5.6'da tanımlanan artımlı güncelleme, üçüncü katmandır. Orijinal baytlar diskte oldukları yerde kalır ve herhangi bir yeni veya değiştirilmiş nesne onların ardına eklenir, ardından orijinale geri zincirlenen taze bir çapraz referans bölümü gelir. Tek bir sayfa eklenmesi gereken 900 MB'lık bir arşiv için, yazma maliyeti farktır, tüm dosya değil
// Büyük bir arşive, onu yeniden yazmadan bir denetim sayfası ekle
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'); // orijinal baytlar + fark
Burada iki disiplin noktası önemlidir. BeginIncrementalUpdate, orijinal dosyayı işaret etmek zorundadır, çünkü eklenen çapraz referans verisi onun içindeki bayt ofsetlerine geri zincirlenir. Ve model tasarım gereği yalnızca eklemelidir: her artımlı kayıt dosyayı büyütür, asla küçültmez. Her gece damgalanan bir belge, periyodik bir yeniden serileştirme, onu yükleyip SaveLoadedDocument üzerinden geri yazma, onu sıkıştırana kadar sınırsız şişer. Aynı yalnızca-ekleme doğası, artımlı güncellemeyi dijital olarak imzalanmış bir belgeye dokunmanın tek güvenli yolu yapan şeydir, bu kısıtlama dijital imzalar ve PAdES makalesinde incelenir. Altta yatan çapraz referans mekaniği kendi işlemesini nesne akışları ve artımlı güncellemeler makalesinde bulur
Yalnızca-eklemeli kayıtlarda çoğu incelemeden kaçan bir tuzak var. Orijinal baytlar dosyada kalır, bakmak isteyen herkes için okunabilir halde. Bir sayfayı "değiştiren" bir artımlı güncelleme eskisini silmez; önceki revizyon tamamen kurtarılabilir halde otururken onu geçerli revizyonda geçersiz kılar. Bu yüzden artımlı güncellemeler hassas içeriği çıkarmak için yanlış araçtır. Bir alıcının asla görmemesi gereken geçmişi gerçekten atmak için, tam bir yeniden serileştirmeye ihtiyacınız var: yalnızca geçerli durumu yazan ve gömülü revizyonları geride bırakan LoadFromFile'ı izleyen SaveLoadedDocument
Katmanı işlemle eşleştirmek
Seçim mantığı aklınızda tutabileceğiniz kadar kısadır ve her işin kendi yolunu doğaçlama yapmasına izin vermek yerine bunu bir hattın başında açık bir yönlendirme kararı olarak kodlamak kazandırır. İhtiyacınız olan işlem katmanı belirler:
- Saymak, incelemek ya da sınıflandırmak bir tutamaç açar:
DAOpenFileReadOnly,DAGetPageCount,DACloseFile - Tüm bir dosyayı taşımak, şifresini çözmek ya da şifrelemek,
DACopyFile,DecryptFileya daEncryptFileile dosya düzeyinde kalır - Sayfaları yeniden yapılandırmak ya da belgeleri birleştirmek, tam yüklemeye ihtiyaç duyar:
LoadFromFile, ardındanInsertPagesFromDocumentya daMovePage, ardındanSaveLoadedDocument - Büyük ya da imzalı bir dosyaya küçük bir fark eklemek,
BeginIncrementalUpdate'i çağırır ve kaydeder
Karışık hatlar, tam yükleme yolunun önüne bir boyut eşiği koyduğunda iyi sonuç verir. Birkaç yüz megabaytı aşan her şeyi Direct File katmanları üzerinden gönderin ve tam yüklemeyi gerçek bir bellek bütçesine sahip 64 bit bir işçide gerçek yeniden yapılandırma için ayırın. Eşik, bir bellek yetersizliği çökmesini görebileceğiniz ve ayarlayabileceğiniz bir yönlendirme kararına dönüştürür
Hangi katman bir işi ele alırsa alsın, çıktısını geçici bir ada yazın ve sonuç doğrulandığında ancak o zaman yerine yeniden adlandırın. Son ad altında oturan yarım yazılmış bir dosya, hattın bir sonraki aşamasına tam olarak iyi bir dosya gibi görünür ve Direct File çağrıları kontrolü ucuz yapar: bir çıktıyı doğrulamak tek satırlık bir tutamaç yoklamasıdır
Direct File API, Delphi ve C++Builder için HotPDF Delphi Component'in bir parçası olarak gönderilir. Ürün sayfası, burada gösterilen artımlı güncelleme çağrıları dahil, tam fonksiyon referansına bağlantı verir