Teknik Makale

Delphi'den Büyük Bir XLSX'te Tek Bir Çalışma Sayfasını Yamalama

HotXLS, dosyanın geri kalanını ayrıştırmadan veya yeniden sıkıştırmadan, mevcut bir XLSX paketindeki tek bir çalışma sayfasını yeniden yazabilir. TXLSDirectWriter.BeginPatch, bir kaynak paketi açar, hedef sayfa dışındaki her girdiyi sıkıştırılmış baytlarıyla harfiyen kopyalar ve o tek sayfayı sıradan AddSheet, AddRow ve Write* çağrıları üzerinden yeniden yazmanıza izin verir. Grafikler, pivot önbellekleri, temalar, biçemler ve paylaşılan dizeler hiçbir zaman açılmaz (decompress)

Bunun çözdüğü iş akışı, raporlamada ve veri yenilemede karşımıza çıkar. Bir iş ekibinden, pivot tablolar, dilimleyiciler (slicer), koşullu biçimler ve on yıllık birikmiş biçimlendirme taşıyan bir çalışma kitabı gelir. Her gece bir veri sayfasının taze sayılarla değiştirilmesi gerekir. Tüm çalışma kitabını yükleyip yeniden kaydetmek, dosya başına dakikalar sürer ve daha önemlisi, yükleme motorunun yeniden oluşturmak zorunda olduğu özelliklerde sadakat riski taşır. Yamalama, ihtiyaç duymadığı şeye dokunmayarak her iki sorunu da atlatır

Sıkıştırılmış baytları kopyalamak neden ilginç kısımdır?

Sıkıştırılmış düzeyde kopyalanan bir zip girdisi, bir akış kopyalamaya mal olur. Aynı girdi normal bir yazma yolundan geçtiğinde, girişte bir açma (inflate) ve çıkışta bir sıkıştırma (deflate) maliyetine sahip olur ve deflate pahalı olan yarısıdır. Büyük bir pivot önbelleğine ve birkaç düzine gömülü görüntüye sahip bir çalışma kitabında bu fark, yeni sayfayı yazma süresinde biten bir yamalama ile zamanının çoğunu hiç incelemediği baytları yeniden sıkıştırarak geçiren bir yamalama arasındaki farktır

HotXLS bunun için, kaynak girdinin sıkıştırılmış baytlarını doğrudan hedef arşive yazan CopyCompressedFrom'u kullanır. Bir girdi, farklı bir sıkıştırma yöntemi veya zayıf şifreleme kullandığı için bu şekilde kopyalanamadığında, yazıcı başarısız olmak yerine açılmış bir akış kopyasına geri döner. Dizin işaretçisi girdileri atlanır, çünkü yazıcı kendi girdilerini üretir

Yerinde değiştirme veya yeni bir dosyaya yazma

İki aşırı yükleme (overload), bu görevin aldığı iki biçimi kapsar. Yerinde biçim, sonucu orijinalin yanında geçici bir dosyada hazırlar, kaynak tanıtıcıyı (handle) kapatır, ardından siler ve yeniden adlandırır, bu yüzden yazma sırasında bir çökme orijinali bozulmadan bırakır. Açık hedefli biçim ise kaynağa dokunmaz ve bir sayfayı değiştirebilir ya da yenisini ekleyebilir:

var
  W: TXLSDirectWriter;
begin
  W := TXLSDirectWriter.Create;
  try
    W.BeginPatch('monthly-dashboard.xlsx', 'Data');   // yerinde
    W.AddSheet('Data');
    W.AddRow(1);
    W.WriteString(1, 'Region');
    W.WriteString(2, 'Revenue');
    W.AddRow(2);
    W.WriteString(1, 'North');
    W.WriteNumber(2, 184320.55);
    W.AddRow(3);
    W.WriteFormula(1, '=SUM(B2:B2)');
    W.Close;
  finally
    W.Free;
  end;
end;

Ekleme varyantı, bir kaynak ve bir hedef yol artı InsertSheet alır:

  // Kaynak dokunulmadan kalır; hedef, Extra adında ekstra bir çalışma sayfası alır
  W.BeginPatch('template.xlsx', 'output.xlsx', 'Extra', True);
  W.AddSheet('Extra');
  W.AddRow(1);
  W.WriteString(1, 'appended by the nightly job');
  W.Close;

Ekleme, gerçek kayıt tutma (bookkeeping) ameliyatı gerektiren kısımdır. Yazıcı, xl/workbook.xml içindeki sayfa kütüğünü ve her sayfayı kendi parçasına bağlayan ilişki haritasını ayrıştırır, ardından bir sonraki boş parça numarasını, sayfa tanımlayıcısını ve ilişki tanımlayıcısını seçer. İlişki türleri kaynak paketin kurallarını izler, bu yüzden katı bir ISO 29500 çalışma kitabını yamalamak katı ilişki türleri üretir, geçişli bir kitabı yamalamak ise geçişli türler üretir

Yamalamanın kasıtlı olarak bıraktığı ve kısıtladığı şeyler

Hesaplama zinciri her iki modda da atılır. Değiştirme modunda, girdileri artık o biçimde var olmayan bir sayfadaki hücreleri tanımlar; ekleme modunda ise sayfa indeksi kayması onu doğrudan geçersiz kılar. Excel, bir sonraki yeniden hesaplamada zinciri yeniden oluşturur, bu yüzden onu bırakmak kayıp değil doğrudur. Parça kopyanın dışında bırakılır ve ilişki girdisi ile içerik türü geçersiz kılması cerrahi bir şekilde kaldırılır

Bir yamalama içinde iki yazma anlambilimi değişir ve ikisi de aynı ilkeden gelir: yamalama, yeniden yazmadığı parçaları rahatsız etmemelidir. Dizeler, paylaşılan dize tablosuna eklenmek yerine doğrudan sayfaya satır içi (inline) yazılır, çünkü kaynak tablo dokunulmadan aktarılır. Ve StyleIndex, yazıcının oluşturduğu bir biçem tablosuna değil, kaynak paketin cellXfs'indeki girdilere işaret eder. Bu, orijinal çalışma kitabının zaten tanımladığı biçemlere başvurabileceğiniz anlamına gelir — ki bu genellikle bir veri yenilemenin tam olarak istediği şeydir — ama aynı zamanda hangi indeksin hangi biçemi taşıdığını bilmeniz gerektiği anlamına da gelir

// Bir yamalama içinde StyleIndex, KAYNAK paketin cellXfs'ini indeksler.
// Bir tarihin, orada bir tarih biçemine eşlenen açık bir indekse ihtiyacı vardır:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);

// Biçemsiz WriteDateTime aşırı yüklemesi, yamalama modunda reddedilir,
// çünkü bu, yazıcının kendi biçem tablosunu varsayar; ki bir yamalama
// bunu hiçbir zaman oluşturmaz

Altı yazma giriş noktası kapı altındadır: tablo, grafik, görüntü, yorum, tanımlı ad ve hücre biçemi eklemenin hepsi yamalama modunda bir istisna fırlatır; kapanış sırasında sayaçlarından herhangi biri sıfır değilse başarısız olan ikinci bir güvenlik ağı da vardır. Bu özelliklerin her biri, yamalamanın harfiyen kopyaladığı parçaların düzenlenmesini gerektirirdi ve yarı düzenlenmiş bir paket, reddedilmiş bir işlemden daha kötüdür. İşlem başına tam olarak bir sayfa yamalanabilir

Ne zaman yamalamalı, ne zaman yüklemeli?

Yamalama, çalışma kitabı büyük olduğunda, değişiklik tek bir sayfayla sınırlı olduğunda ve dosyanın geri kalanının bit bit hayatta kalması gerektiğinde doğru araçtır. Değişiklik birkaç sayfaya yayıldığında, yeni biçimlendirme veya yeni nesneler gerektiğinde ya da dosya normal bir yükleme ve kaydetmenin hiçbir maliyeti olmayacak kadar küçük olduğunda ise yanlış araçtır. Sıfırdan toplu üretim için, akış doğrudan yazıcısı yazısında anlatılan akış yolu daha uygun seçim olmaya devam eder ve aynı AddRow ve Write* API'sini paylaşır, bu yüzden ikisi arasında geçiş mekaniktir

Tam nesne modelini gerçekten istediğinizde, yüklenmiş bir çalışma kitabı içinde sayfa düzeyinde manipülasyon, XLSX paketlerinde çalışma sayfalarını çoğaltma yazısında ele alınmıştır. Ve bir yamalamayı düşünmenizin nedeni tüm çalışma kitabı işlemenin yavaşlaması ise, bir yaklaşım seçmeden önce büyük çalışma kitabı performansı yazısındaki ölçümleri ve bellek davranışını okumaya değer

Bir yamalamanın gerçekten düşündüğünüzü yaptığını doğrulamak

Üç kontrol neredeyse her hatayı yakalar. Hayatta kalmasını beklediğiniz parçaların hâlâ arşivde olduğunu, xl/calcChain.xml'in gittiğini ve dosyayı TXLSXWorkbook üzerinden yeniden açmanın beklediğiniz sayfa sayısını — bir değiştirme için değişmemiş, bir ekleme için bir artmış olarak — bildirdiğini doğrulayın. Yamalanan sayfayı geri okumak ve birkaç değeri ve formülü karşılaştırmak döngüyü kapatır

Bu özelliğin geliştirilmesinden gelen bir uygulama ayrıntısı tekrarlanmaya değer, çünkü benzer zip düzeyi kod yazan herkesi ısırabilir. Çalışma sayfası parça adları önekle eşleştirilir ve önek uzunluğunda birlik hatası (off-by-one), yüklemin hiçbir zaman eşleşmediği anlamına gelir, bu yüzden yeni yazılan bir parça mevcut bir adla çakışır ve belirli bir adla son girdiyi alan okuyucular sessizce yanlış sayfayı seçer. Bir yamalama iki sayfanın içeriğini takas etmiş gibi görünüyorsa, XML'e bakmadan önce ad eşleştirmesine bakın

Yerinde yamalama, akış yazmaları ve tam çalışma kitabı nesne modeli, Delphi ve C++Builder için aynı kütüphanede gelir; özellik listesi HotXLS Delphi elektronik tablo bileşeni sayfasındadır