BIFF PivotCache alt akışı, bir PivotTable önbelleklenmiş veri kümesini onu görüntüleyen görünümden ayrı saklar ve HotXLS o alt akışı, kayıt numaralarına güvenmek yerine kayıt gövdelerini inceleyerek okur ve yazar. Ayrımın öyküsü tam olarak budur: aynı kayıt numarası, dosyayı hangi yazıcının ürettiğine göre birbiriyle uyumsuz iki gövde düzeni taşır; okuyucu çerçevelemeyi gördüğü ilk kayıt gövdesinden karar verir
Bu katmanla, bir PivotTable'ın gidiş-dönüşten sağ çıkması gerektiği anda tanışırsınız. Önbelleksiz bir pivot görünümü bir kabuktur ve Excel dosyayı açtığında önbelleği kaynak aralıktan yeniden kurar; bu, kaynak aralığın yok olduğu, verinin bir sorgudan yapıştırıldığı ya da çalışma kitabının, biri açtığında değişmemesi gereken arşivlenmiş bir dönem kapanışı olduğu noktaya kadar sorun değildir
İki yapı, dosyada iki yer
Önbelleklenmiş veri ile önbellek tanımı, çalışma kitabının farklı kısımlarında yaşar ve ikisini birbirine karıştırmamak düzeltilecek ilk şeydir. Önbelleklenmiş kayıtlar kendi alt akışlarını oluşturur; [MS-XLS] §2.1.7.12 bunu PIVOTCACHE = SXDB SXDBEx *SXFORMULA *FDB *DBB EOF olarak verir. Neyin yok olduğuna dikkat: o üretimin başında BOF yoktur
Tanım ise bunun yerine çalışma kitabı globals'ında, PIVOTCACHEDEFINITION = SXStreamID SXVS [SXSRC] [SXADDLCACHE] (§2.1.7.20.3) olarak durur; biçimlendirme kayıtlarının ardından, BoundSheet ile Country kayıtlarından önce konumlanır. Yani tek bir önbellek, yüzlerce kayıt arayla iki yerde tarif edilir ve aralarındaki bağ, üç konumda aynı anda uyuşmak zorunda olan bir akış tanımlayıcısıdır
Her önbellek, _SX_DB_CUR altında bir akışa aittir; adı, tanımlayıcısının dört haneli büyük harf onaltılık yazımıdır. SXStreamID.idStm, SXDB başlığında yinelenen idstm alanı ve o akış adının üçü de eşleşmek zorundadır. Yeni bir tanımlayıcı ayırırken önce dosyadan hâlihazırda okunmuş her numarayı rezerve edin; yoksa yeni bir önbellek, okuyucunun henüz yürümediği eski bir önbelleğe ait bir numaraya sahip çıkabilir
İnsanları yakalayan bir tanımlayıcı daha var. Bir pivot görünümündeki iCache değeri, ilgili SXStreamID'nin global dizideki sıfır tabanlı konumudur, seçebileceğiniz bir önbellek tanımlayıcısı değil. Yazarken önbellek nesnesinden gerçek çıktı konumuna eşlenmek zorundadır ve mevcut görünümler de onunla birlikte yeniden numaralandırılmalıdır; yoksa bir önbelleği yükseltmek, bir görünümü sessizce başka birine yöneltir
var
Book: TXLSWorkbook;
Cache: TXLSPivotCache;
Field: TXLSPivotCacheField;
V: TXLSPivotCacheValue;
begin
Book := TXLSWorkbook.Create(nil);
try
Book.LoadFromFile('sales.xls');
Cache := Book.PivotCaches.Add;
Cache.SourceRangeSheet := 'Data';
Cache.SourceFirstRow := 1; Cache.SourceFirstCol := 1;
Cache.SourceLastRow := 500; Cache.SourceLastCol := 6;
Cache.SourceDataType := 1; // SXVS SHEET, MS-XLS 2.4.317
Cache.RefreshOnLoad := False; // önbellekteki kayıtlara güven
Cache.SaveData := True;
Field := Cache.AddField('Region', xlpcftString);
V.ValueType := xlpcftString;
V.StrValue := 'North';
Field.FindOrAddItem(V);
Cache.SetRecordCount(0); // temizle, sonra kayıt ızgarasını boyutlandır
Cache.SetRecordCount(500);
Book.StorePivotCaches;
finally
Book.Free;
end;
end;
Çift SetRecordCount batıl inanç değildir. RecordCount tahsis yapmayan sıradan bir özellik yazımıdır ve iç büyüme yolu yalnızca yeni eklenen satırları ilklendirir; sayısı başlık yoluyla kurulmuş bir önbellek, sıfır uzunlukta bir indeks ızgarasıyla kalabilir. RecordIndices'e yapılan yazımlar sonra hatasızca çöpe gider. Sayıyı sıfıra çekip geri kurmak ızgarayı yeniden tesis eder ve bu, her alan eklendikten sonra gerçekleşmek zorundadır; çünkü satır genişliği alan sayısından gelir
Bir kayıt numarası size gövde düzenini neden söyleyemez?
Çünkü kayıt numaraları ile gövde düzenleri farklı zamanlarda değişti; aralarındaki eşleme bir işlev değildir. Eski setteki bir numara yalnızca daha eski yazıcıların dosyalarında görünür, bu da onu tek yönde güvenilir bir sinyal yapar. Başka bir numara ise gerçekten belirsizdir: hem doğru dosyalarda hem de yeni numarayı eski gövde düzeniyle kullanan bir aralık ara sürümde görünür
Çerçeveleme bu yüzden gövdeden karara bağlanmak zorundadır ve kayıt başına değil, her önbellek alt akışı için bir kez. HotXLS lehçeyi, her alt akıştaki ilk SXDBB kaydının uzunluğundan sabitler. Spesifikasyon çerçevelemesinde bir SXDBB tam olarak bir önbellek kaydı taşır; uzunluğu bir satır genişliğine eşittir. Eski paketli çerçevelemede ilk kayıt, sığdığı kadar satır taşır; birden fazla satırlı her önbellek için en az iki satır genişliğidir. İki öngörü ayrıştığında karşılaştırma belirleyicidir
Ayrışmadıklarında okuyucu spesifikasyon okumasını alır; ilke, Excel'in yazdığı dosyaların ara bir derlemenin yazdıklarından çok daha fazla olduğudur. O kör nokta kurgu gereği dardır ve gerçekleştiğinde bile dosyanın kendisi bayt bayt aynen oynatılır. Yalnızca çağıranlara açılan tipli indeksler etkilenir
İndeks genişliği başka bir kayıtta yaşar
SXDBB (§2.4.276), ayrık değer bayrağı kurulmuş her önbellek alanı için alan sırasınca bir indeks taşır ve her indeksin genişliğine başka yerde karar verilir: karşılık gelen SXFDB alan kaydı (§2.4.283) bir kısa öğe bayrağı bildirir ve o bayrak, indeksin iki bayt mı bir bayt mı kapladığını söyler. İki kayıt, tek zımni sözleşme ve onları birbirine bağlayan spesifikasyondaki tek bir cümle
O eşleşme, ev yapımı bir kodlamanın tam yanıldığı yerdir. Eski bir HotXLS yazıcısı her alanı minimum bit sayısına paketliyor, satırlar arasında bayt sınırına dolduruyordu; tek başına savunulabilir ama aynı yazıcının az önce SXFDB içinde bildirdiği genişlikle doğrudan çelişiyordu. Üç ayrık değerli bir alan, bir kayıtta bir bayt genişliğinde tarif edilirken öbüründe iki bit kaplıyordu. Düzeltme aritmetiği düzeltmek değildi; genişlik kararını her iki yayıcının da çağırdığı tek bir işleve çıkarmaktı, böylece iki kayıt artık ayrışamaz. BIFF kayıt uzunluğu bildirim sapması makalesinde tarif edilen kusur sınıfı da budur: bildirilen boyut ile gerçek gövde yollarını ayırır
Bu kayıtları hiç okumamanın sonucunu açıkça söylemeye değer; hafife alınması kolaydır. Okuyucu kayıt indekslerini atladığında, dosyadan yüklenen her önbellek her satırın her alanı için indeks sıfır bildiriyordu; yani her satır, her alanın ilk değerini işaret ediyordu. Bu yalnızca azalmış içe bakış değildir: pivot değerlendirme yolu da önbellekten hücreye doldurma yolu da o ızgarayı tüketir. Ve gidiş-dönüş bir test bunu yakalayamaz; çünkü hâlâ ham oynatmadaki bir önbellek orijinal baytlarından geri yazılır
// Kaynak (provenance) bayrakları elinizde neyin olduğunu ve neyin yeniden yazılabileceğini söyler
if Cache.FromRawBlobs then
begin
Writeln('stream id : ', IntToHex(Cache.StreamId, 4));
Writeln('legacy framing : ', Cache.RawFramingIsLegacy);
Writeln('own storage : ', Cache.RawHasStorageStream);
Writeln('model complete : ', Cache.RawModelIsComplete);
// Yeniden yayım, yalnızca her kaydın burada modeli varken kayıpsızdır
if Cache.CanUpgradeFraming then
Writeln('safe to rewrite with the current emitters');
end;
Bir önbelleği yeniden yazmak ne zaman kayıpsızdır?
Yalnızca üç koşul birlikte tuttuğunda ve soruyu cevaplayan tek özellik CanUpgradeFraming'dir. Önbellek hâlâ ham oynatmada olmalı, alt akış bu kütüphanenin daha önce yanlış yazdığı çerçevelemelerden birinde olmalı ve okuyucu içindeki her kaydın eksiksiz bir tipli modelini kurmuş olmalı. Excel'in yazdığı bir önbellek asla uygun düşmez; çünkü alt akışı HotXLS'in modeli olmayan kayıtlar taşır ve modelden yeniden yazım onları düşürürdü
Eksiksizlik testi ilk bakışta göründüğünden daha katıdır. Okuyucunun yalnızca opak bayt olarak tuttuğu bir kayıt, modeli eksik işaretler. Yayıcının yeniden üretemediği bildirilmiş bir formül kaydı sayısı da öyle; çünkü yeniden yazım, birkaç formül kaydı bildirimini hiçbir formül kaydı bildirimi olarak yeniden yazar ve dosyada yeniden üretilemeyen bir değer, yeniden üretilemeyen bir kayda denktir
Bilinçli muhafazakarlık yazıcıdan da geçer. İndeksler, bant dışı bir sentinel olarak kodlanmak yerine yasal aralığa kırpılır; çünkü spesifikasyon, ayrık değer dizisine bir indeks tanımlar, başka hiçbir şeyi değil ve boş bir hücre de o dizide bir değerdir. BIFF kayıt tavanını aşan bir önbellek kaydı gövdesi hiç yazılmaz; bu binlerce önbellek alanı gerektirir ve BIFF8 sütun sınırı içinde zaten ulaşılamaz; yedek, Excel'in kaynak aralıktan tazelemesidir ki bu bozuk dosya değil tanımlı davranıştır
Tarihler kayıtlar arası son bağımlılığı taşır. Seriden tarihe dönüşüm, çalışma kitabının tarih sistemine bağlıdır ve kayıt yayıcısı kitabı göremez; bu yüzden taban tarih tercihi, varsayılanı 1900 sistemi olan ve kitap düzeyindeki kayıt yolu tarafından sağlanan bir parametre olarak geçilir. 1900 sistemi altında seri numarası değerin kendisidir; 1904 sistemi 1462 gün farklıdır. Tarih serilerinin daha geniş ele alınışı, tarih serileri, 1904 sistemi ve sayı formatları makalesindedir
Önbellek katmanında değil görünüm katmanında çalışıyorsanız görünür pivotu tarif eden kayıtlar BIFF8 PivotTable kayıt seti makalesinde, hesaplama tarafı davranış ise hesaplanan alanlar, hesaplanan öğeler ve tazeleme makalesinde ele alınır. Üç katman da HotXLS Delphi spreadsheet bileşeni içinde gelir; eski bir çalışma kitabını yükleyip önbelleğinin gerçekte ne içerdiğine bakmayı ve yeniden yazmanın güvenli olup olmadığını yapmadan önce karar vermeyi mümkün kılan da budur