Yerel Delphi ve C++Builder Excel kitaplığı HotXLS, Excelin bir formülün yanında zaten depolamış olduğu değeri TryGetCachedFormulaValue ve IXLSFormulaCacheReader aracılığıyla okur. Bu giriş noktalarının hiçbiri hesaplayıcıyı çağırmaz, formül belirteçlerinin derlemesini açmaz, kirli durumu güncellemez ve modele geri hiçbir şey yazmaz; böylece yalnızca okuduğunuz bir çalışma kitabı tam olarak açtığınız gibi kalır
Bunu gerektiren senaryo sıkıcı ve son derece yaygındır. Gece çalışan bir iş, başkalarının ürettiği birkaç yüz çalışma kitabını açar, her birinden toplamlardan oluşan bir sütun çeker ve sayıları bir veri ambarına basar. Toplamlar zaten dosyaların içindedir — Excel bunları hesaplamış ve kaydetmiştir. Ancak iş, formül hücresinden değerini istediği anda, bu soruya tek bir yanıtı olan bir kitaplık bir bağımlılık grafiği kurar ve tüm sayfayı değerlendirir; G/Ç yoğun olması gereken bir iş, bir hesaplama kıyaslamasına dönüşür
Bir formül hücresini okumak neden tam bir yeniden hesaplamaya mal olur?
Çünkü bir formül hücresindeki değer alıcısı, bir değer üretme isteğidir ve bir değer üretmenin evrensel olarak doğru tek yolu formülü değerlendirmektir. Bu, çalışma kitaplarını düzenleyen bir uygulama için doğru varsayılan, onları çıkaran bir işlem hattı için yanlış varsayılandır. Daha da kötüsü, değerlendirme yan etkilerden uzak değildir: sonuçları hücrelere geri yazar, kirli bayrakları değiştirir ve bir işlev desteklenmediğinde ya da dış başvuru bozuk olduğunda, üreten uygulamadan farklı bir sonuç verebilir. Operasyon ekibine salt okunur olarak tanımladığınız bir iş, sessizce disktekiyle artık eşleşmeyen bir çalışma kitabı üretir ve daha sonra herhangi bir şey onu kaydederse diskteki dosya da değişir
Önbellekli değer okuma, sözleşmenin diğer yarısıdır. Daha dar bir soruyu yanıtlar — üreten uygulama buraya ne depoladı? — ve başka hiçbir şeyi yanıtlamayı reddeder. Gerçekten taze sayılar istediğinizde HotXLS size yine de bağımlılık grafiğiyle yürüyen artımlı yeniden hesaplama sunar; mesele şu ki çıkarma ve değerlendirme iki farklı çağrı olmalıdır, iki ruh hali olan tek bir çağrı değil
Tek bir hücre hakkında üç birbirinden bağımsız gerçek
Önce sonuç: önbelleğe alınmış bir formül değeri üç bağımsız gerçek taşır ve bunları tek bir Variant içinde birleştirmek ihtiyaç duyduğunuz bilgiyi kaybettirir. TXLSFormulaCacheInfo bunları State, Kind ve Value olarak ayrı tutar. TXLSFormulaCacheState kaynağı beş durumda kaydeder — xlfcsNotFormula, xlfcsMissing, xlfcsLoaded, xlfcsCalculated ve xlfcsInvalidated — TXLSFormulaCacheValueKind ise yükü xlfcvBlank, xlfcvNumber, xlfcvDateTime, xlfcvString, xlfcvBoolean ya da xlfcvError olarak sınıflandırır. Bu ayrım, varlığın dürüstçe bildirilebilmesini sağlayan şeydir: önbelleğe alınmış bir boşluk, önbelleğe alınmış boş bir dizge, önbelleğe alınmış bir False, önbelleğe alınmış bir sıfır ve önbelleğe alınmış bir hata, hepsi gerçek değerlerdir; bu nedenle varlık asla VarIsEmpty ya da VarIsNull ile çıkarılamaz. TryGetCachedFormulaValue yalnızca xlfcsLoaded ve xlfcsCalculated için True döndürür ve False döndürdüğünde bile tanı konabilir bir durumu doldurur
var
Book: TXLSXWorkbook;
Info: TXLSFormulaCacheInfo;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('quarterly-model.xlsx');
// SheetIndex, Row ve Col burada hep 1 tabanlıdır
if Book.TryGetCachedFormulaValue(1, 12, 5, Info) then
Writeln('cached value: ', VarToStr(Info.Value))
else
Writeln('no usable cache, state ordinal ', Ord(Info.State));
finally
Book.Free;
end;
end;
Önbelleğe alınmış değer neden eksik?
TryGetCachedFormulaValue işlevinin False döndürmesinin tam olarak dört nedeni vardır ve durum hangisinin geçerli olduğunu söyler. xlfcsNotFormula, hücrenin bir hazır değer taşıdığını ya da tamamen boş olduğunu belirtir; koordinatların aralık dışı olması da aynı yanıta birleşir. xlfcsMissing, hücrenin gerçekten bir formül olduğu ancak üreticinin onun için hiçbir değer yükü depolamadığı anlamına gelir; bir üretici formülleri yazıp sonuçları ilk açılışta Excelin doldurmasına bıraktığında sık görülen bir sonuçtur. xlfcsInvalidated, formül metninin yüklemeden sonra değiştirildiği anlamına gelir; dolayısıyla eskiden orada bulunan değer, artık var olmayan bir ifadeyi tanımlar. Buna karşılık xlfcsCalculated bir başarı durumudur: dosyadan gelen xlfcsLoaded durumunun aksine, bu oturumda kendi kodunuzun ya da HotXLS değerlendiricisinin ürettiği bir değeri işaretler
Eksik bir önbellek konusunda dürüst olmak, onun üstünü örtmekten daha önemlidir. HotXLS bir değer icat etmeyi reddeder ve kaydederken de aynı ölçüde katıdır: yalnızca xlfcsLoaded ve xlfcsCalculated önbellekli bir değer yayar; xlfcsMissing ve xlfcsInvalidated ise dosyaya bayat bir sayı dondurmak yerine yalnızca formülü yazar. Bu da bir işlem hattında size üç makul yanıt bırakır: satırı atlayıp boşluğu kaydetmek, o tek çalışma kitabını bilinçli olarak yeniden hesaplatıp maliyetini kabul etmek ya da değerlendirip mutabakat sağlamak. Değerlendirilen sayı, üreten uygulamanın yazacağıyla aynı fikirde değilse, formül değerlendirme izleyicisi, sonuçtan tahmin yürütmek yerine iki hesaplamanın nerede ayrıştığını bulma aracıdır
Klasik, OOXML ve ODF motorlarında tek bir okuyucu
Bir işlem hattı, az önce açtığı dosyanın BIFF, OOXML ya da ODF olduğunu önemsememelidir. IXLSFormulaCacheReader, üçünün de tek salt okunur giriş noktasıdır: hem TXLSWorkbook.CreateFormulaCacheReader hem de TXLSXWorkbook.CreateFormulaCacheReader, her motorun zaten kullandığı seyrek hücre aramasının üzerinde, aynı 1 tabanlı sayfa, satır ve sütun koordinatlarıyla hafif bir bağdaştırıcı döndürür. Çalışma kitabı sınıfları, arabirimi bilinçli olarak kendileri uygulamaz; çalışma kitabına yönelik bir arabirim başvurusu, sahiplik semantiğini değiştirir ve çağıranların yaşam süresi kira sözleşmesini geçmesine izin verebilir. Bunun yerine, çalışma kitabının yok edilmesi o kira sözleşmesinin içindeki ham işaretçiyi temizler ve kodunuzun elinde tuttuğu herhangi bir okuyucu, bir sonraki sorgusunda boşaltılmış belleğe erişmek yerine EXLSFormulaCacheReaderInvalidated hatası verir. Bu bir eşzamanlılık garantisi değil, hızlı başarısız olan yaşam süresi denetimidir
var
Reader: IXLSFormulaCacheReader;
Info: TXLSFormulaCacheInfo;
Row, Missing, Errors: Integer;
Total: Double;
begin
Reader := Book.CreateFormulaCacheReader;
Total := 0;
Missing := 0;
Errors := 0;
for Row := 2 to LastRow do
if Reader.TryGetCachedFormulaValue(1, Row, 7, Info) then
begin
case Info.Kind of
xlfcvNumber: Total := Total + Double(Info.Value);
xlfcvError: Inc(Errors);
end;
end
else if Info.State = xlfcsMissing then
Inc(Missing);
// Hiç hesaplayıcı çalışmadı, hiç kirli bayrak oynamadı, Book değişmedi
end;
Önbelleğe alınmış baytlar gerçekte nerede yaşar
Klasik .xls dosyaları için önbellek, Formula kaydının FormulaValue alanıdır; [MS-XLS] §2.5.133 tarafından tanımlanan sekiz bayttır. Yüksek sözcük $FFFF olduğunda yük bir IEEE 754 çift duyarlıklı sayı değil, etiketli bir varyanttır ve yerleşim ince ayrıntılarıyla kolayca yanlış yapılabilir: varyant türü val[0] içindedir ve Boolean ya da BErr yükü val[2] içindedir; val[1] tanımsızdır. HotXLS daha önce yükü val[1] konumundan okuyordu; bu, yalnızca sayı yerine Boolean ya da hata önbelleğe alan belirli dosyalarda ortaya çıkan türden bir birim kaymasıdır. Okuyucu ve paylaşılan formül yazarı artık aynı uzaklıklar üzerinde anlaşmıştır; böylece önbelleğe alınmış bir TRUE, yüklenip kaydedildiğinde gürültüye dönüşmek yerine bozulmadan hayatta kalır
Paket biçimlerinde tür sadakati, kendi tuzağı olan ayrı bir sorundur. OOXML içinde önbellekli değer, c öğesine <v> olarak asılır ve t özniteliği türü ECMA-376 Part 1 §18.3.1.4 uyarınca adlandırır. HotXLS t="e" değerini doğrudan bir varError Variant içine okur ve kaydederken standart hata metnine geri eşler; böylece hatalar asla sıradan tamsayılar kılığına girmez — ama Delphi RTL burada size yardım etmez, çünkü VarAsType(Integer, varError) bir dönüştürme özel durumu yaratır. Çalışan kurulum, TVarData.VType ve TVarData.VError alanlarını doğrudan ayarlar. Tarihler aynı disiplini ters yönde izler: t="d" ve ODF tarih değer türü açık tür bildirimleridir ve varDate haline gelir; bir BIFF sayısal önbelleği ise hiç tarih bayrağı taşımaz ve bu nedenle Double kalır. HotXLS asla bir hücrenin sayı biçiminden tarih tahmin etmez, çünkü sayı biçimi sunumdur, önbellek ise veridir. ODF, bilinmeye değer bir durum daha ekler — office:value-type="void", var olan ama değer taşımayan bir önbelleği ifade eder ve ODFin hata değer türü olmadığından, hata gibi görünen metin hataya yükseltilmek yerine metin olarak korunur
function DescribeCache(const Info: TXLSFormulaCacheInfo): string;
begin
case Info.State of
xlfcsNotFormula: Result := 'not a formula cell';
xlfcsMissing: Result := 'formula stored with no cached value';
xlfcsInvalidated: Result := 'formula replaced since load';
else
case Info.Kind of
xlfcvError: Result := 'error code ' + IntToStr(TVarData(Info.Value).VError);
xlfcvDateTime: Result := DateTimeToStr(VarToDateTime(Info.Value));
xlfcvBoolean: Result := BoolToStr(Info.Value, True);
xlfcvNumber: Result := FloatToStr(Double(Info.Value));
xlfcvString: Result := VarToStr(Info.Value);
else
Result := 'present but blank';
end;
end;
end;
Paylaşılan formüller önbelleğe alınmış değerlerini paylaşır mı?
Hayır, tersini varsaymak, bir taramanın tüm sütun için aynı sayıyı bildirmesiyle sonuçlanma yoludur. Bir OOXML paylaşılan formülü, yalnızca formül ifadesini ve depolama iyileştirmesini paylaşır; her üye hücre kendi <v> değerine hâlâ kendisi sahiptir. Bu nedenle HotXLS, kök üye önbelleğini değersiz gelen bir izleyiciye asla yaymaz ve xlfcsMissing olarak yüklenen bir izleyici, kaydetme ve yeniden açma sonrasında da xlfcsMissing bildirir. Grubun ilk olarak nasıl depolanıp genişletildiğini inceliyorsanız, paylaşılan formül si özniteliğinin ve genişletilmesinin mekaniği ayrı olarak ele alınmıştır; önbellek okuma için kural tek satıra iner — her hücreye sor, istemediğin hiçbir şeye güvenme
Önbellekli değer okuma, birleşik motorlar arası okuyucu ve çağırmamayı seçebileceğiniz yeniden hesaplama motorunun hepsi, Delphi ve C++Builder için standart HotXLS Delphi Spreadsheet Component ürününde sunulur; Excel ya da herhangi bir OLE otomasyon sunucusuna bağımlılık yoktur; ürün sayfası burada gösterilen çalışma kitabı ve okuyucu giriş noktalarının tam API başvurusunu taşır