On bin elektronik tabloyu bir gecede toplu dönüştürmeyi çalıştırın, sabah üç tanesi False döner. Bir boolean kayıt sonucunun size verdiği tüm otopsi budur: hangi dosya, hangi sayfa veya bir düzine olası nedenden hangisi sorumlu hakkında hiçbir şey olmadan bir başarısızlık sayısı. losLab'ın Excel dosyaları için yerel Delphi ve C++Builder bileşeni olan HotXLS, bu tek biti yapılandırılmış tanılamayla değiştirir. IXLSWorkbookProgress arayüzü, her Open, SaveAs ve Recalculate çağrısı için kararlı bir sayısal kod, bir önem düzeyi, başarısız olan işlemi ve gerçekleştiği sayfayı bildiren bir Diagnostics listesi ile bir OnDiagnostic olayı sunar
Boolean bir kayıt sonucu ölçekte neden yetersiz kalır?
Tek bir başarısız dosya, boolean bir sonucun yarattığı sorun değildir; binlercesi sorundur. On bin dosyadan üçü için SaveAs başarıdan farklı bir şey döndürdüğünde, sonraki soru her zaman aynıdır: bu üçü yeniden denenebilir mi, yoksa bir insana mı ihtiyaçları var? Bir ağ paylaşımındaki bir izin hatası, hesaplama motorunun değerlendiremediği bir formülle aynı olay değildir ve ikisi de sessizce bir format sınırını aşan bir çalışma sayfasıyla aynı değildir. Yalnızca bir geçti/kaldı sonucuyla çalışırken, bunların her biri aynı destek bileti haline gelir ve birinin her dosyayı elle, Excel'de açıp neden belirginleşene kadar bakması gerekir. Bu manuel triyaj, boolean bir API'nin gerçek maliyetidir ve toplu işin boyutuyla doğrusal olarak ölçeklenir ki bu, hata işlemede kesinlikle istemediğiniz özelliktir
IXLSWorkbookProgress'in içi: bir TXLSDiagnostic ne taşır?
IXLSWorkbookProgress, HotXLS'in hem bir işlemin nasıl gittiğini hem de içinde neyin yanlış gittiğini bildirmek için kullandığı arayüzdür ve bu iki yarı bir nedenden dolayı tek bir sözleşmeyi paylaşır: her ikisi de uzun süren bir Open, SaveAs veya Recalculate çağrısının işlem ortasında bir istisna fırlatmadan iletişim kurması gereken şeylerdir. İlerleme yarısı OnProgress ve OnProgressEx'tir; bir aşama, bir durum ve bir mevcut/toplam çiftiyle tetiklenir. Tanılama yarısı bu makalenin konusudur: bir TXLSDiagnostics listesi döndüren bir Diagnostics özelliği, en son giriş için bir LastDiagnostic kısayolu ve her TXLSDiagnostic kaydı oluşturulduğu anda tetiklenen bir OnDiagnostic olayı. Her kayıt, sayısal bir Code, bir TXLSDiagnosticSeverity, onu üreten TXLSDiagnosticOperation, okunabilir bir Message, bir SheetIndex ve SheetName ile girişi tetikleyen alt düzey dönüş değerini ne olursa olsun koruyan bir NativeCode taşır
var
Book: TXLSXWorkbook;
Diag: TXLSDiagnostic;
I: Integer;
begin
Book := TXLSXWorkbook.Create;
try
if Book.SaveAs('quarterly-report.xlsx') <> 1 then
for I := 0 to Book.Diagnostics.Count - 1 do
begin
Diag := Book.Diagnostics[I];
Writeln(Format('[%d] severity=%d sheet="%s": %s',
[Diag.Code, Ord(Diag.Severity), Diag.SheetName, Diag.Message]));
end;
finally
Book.Free;
end;
end;
Diagnostics'i bu şekilde okumak, boolean bir sonucu kendi başına zaten geçer, çünkü Code ve SheetName bir gizemi belirli, filtrelenebilir bir gerçeğe dönüştürür. TXLSDiagnostic kaydı bu örneğin yazdırdığından daha ileriye uzanır: RecordId ve StreamOffset, bir BIFF akışı içinde bayt düzeyinde adli inceleme için vardır ve PartName, bir sorunun geldiği xl/worksheets/sheet3.xml gibi OOXML zip girdisini tutar. Bunların etrafında araç geliştirmeden önce bilinmesi gereken bir şey: mevcut sürümde yerleşik tanılama çağrı noktalarından hiçbiri RecordId veya StreamOffset'i doldurmaz; bu yüzden ikisi de kurucularının varsayılanı olan -1'de kalır, bu da "sıfır" değil "uygulanamaz" anlamına gelir. Bunların yokluğunu işleyicinizde bir hata olarak değil normal olarak ele alın
İki motor, bir biçim, sessiz bir fark
HotXLS, eski .xls dosyaları için bir BIFF8 cephesi ve .xlsx için bir OOXML cephesi olmak üzere aynı raporlama modelinin arkasında iki motor sunar ve bunlar IXLSWorkbookProgress'i özdeş şekilde açığa çıkarmaz. .xls motoru TXLSWorkbook, IXLSWorkbookProgress'i resmi olarak uygular; bu yüzden o arayüz türünün beklendiği her yere geçirilebilir. .xlsx motoru TXLSXWorkbook, aynı Diagnostics, LastDiagnostic, OnDiagnostic, OnProgress ve OnProgressEx üyelerini özdeş adlar ve türlerle sunar, ama bu arayüzün resmi bir uygulaması olarak değil, düz bir sınıf olarak; bu yüzden bir IXLSWorkbookProgress parametresini tek başına karşılamaz. Pratikte bu nadiren önemlidir, çünkü çoğu kod bir seferde tek bir somut çalışma kitabı sınıfına karşı çalışır, ama IXLSWorkbookProgress'e yazılmış tek bir yardımcı yazıp her iki motorun çalışma kitabı nesnesini birbirinin yerine veremeyeceğiniz anlamına gelir. Format ayrımından doğrudan gelen tek alan farkı PartName'dir: yalnızca XLSX motoru bunu doldurur, çünkü yalnızca OOXML'in adlandırılacak zip parçaları vardır
Bir tanılama kodunu neyi güvenle dallanabileceğiniz bir şey yapar?
Code alanı, bir tanılamanın karşısında sabit kodlanmış bir karşılaştırmaya değer tek parçasıdır; Message değildir, çünkü düz metin, kimse bunu kırıcı bir değişiklik olarak ele almadan sonraki bir sürümde yeniden ifade edilecek, yeniden çevrilecek veya daha fazla ayrıntıyla genişletilecek tam olarak türden bir şeydir. HotXLS'in yerleşik tanılama kodları zaten bu ayrım göz önünde bulundurularak tasarlanmış gibi okunur: kaydetmeyle ilgili kodlar 1000'den 1005'e kadar uzanır, açmayla ilgili kodlar 1100 ve 1101'de oturur, hesaplamayla ilgili kodlar 1200 ve 1201'de, desteklenmeyen bir format kodu ise 1300'de; her bandın içinde kodların art arda çalışması yerine boşluklar bırakılmıştır. Bu aralık, bir satıcının, switch deyiminizin zaten bağlı olduğu kodları yeniden numaralandırmadan diyelim 1006'da yeni bir kayıt zamanı başarısızlık modu eklemesine izin veren şeydir ve üretimde bir koda eşleşmeyi taahhüt etmeden önce yalnızca bunu değil herhangi bir tanılama API'sinde kontrol etmeye değer. Numaralandırma ne kadar kararlı görünürse görünsün kendi gönderim mantığınızda bir varsayılan dal tutun, çünkü yeni başarısızlık modları tam olarak gelişen bir ayrıştırıcının veya yazıcının keşfetmeye devam ettiği şeydir. NativeCode ve ExceptionClass, yükseltme yapmanız gerektiğinde Code'un bir katman altında oturur: NativeCode altta yatan dönüş değerini korur, bunların arasında Structured Storage çağrısından bir HRESULT vardır ve ExceptionClass, dahil olduğunda Delphi istisna türünü kaydeder ki bu genellikle tam bir yığın izini eklemeden hassas bir destek talebi açmaya yeter
Önem düzeyi ve işlem, kodunuzun sonraki adımını belirler
Önem düzeyi ve işlem, bir tanılamayı bir günlük satırından bir yönlendirme kararına dönüştüren şeylerdir. TXLSDiagnosticSeverity, Info, Warning, Error ve Fatal olarak uzanır ve TXLSDiagnosticOperation, her girdiyi onu üreten çağrıyla etiketler: Open, Save, Calculate veya Export. İki eksen tasarım gereği bağımsızdır: xlsDiagnosticUnhandledException, gerçekte hangi çağrı fırlattıysa onunla ayarlanmış Operation ile tetiklenen sabit bir koddur; bu yüzden Code neyin yanlış gittiğine, Operation ise ayrı olarak nerede olduğuna yanıt verir; açma sırasında bir istisna için ayrı bir koda, kaydetme sırasındaki için başka birine ihtiyaç duymak yerine. Bu birleştirilebilirlik, yönlendirmeyi mekanik hale getiren şeydir de: bir uyarıyı günlüğe kaydedip devam edin - Aborted bayrağı üzerinden iptal edilen bir kayıt tipik bir örnektir; bir hatayı sayıp toplu işi çalıştırmaya devam edin - serileştirilemeyen bir çalışma sayfası tipik bir örnektir; fatal bir önem düzeyinde toplu işi durdurun, çünkü bu düzey, işlenmemiş bir istisnanın çağrıyı zaten çözdüğü ve devam etmenin yarı güncellenmiş bir durumdan çalışma riski taşıdığı anlamına gelir. Dürüst bir uyarı: Info, taze bir TXLSDiagnostic'in başladığı varsayılan olarak enum içinde vardır, ama bugünkü HotXLS sürümüne yerleşik her tanılama çağrı noktası yalnızca Warning, Error veya Fatal fırlatır; Info ileriye dönük kullanım için ayrılmıştır, motorun bugün yaydığı bir şey değildir
// same Diagnostics loop as above, routed by severity instead of printed flat:
for I := 0 to Book.Diagnostics.Count - 1 do
begin
Diag := Book.Diagnostics[I];
case Diag.Severity of
xlsDiagnosticWarning:
Writeln(Format('WARN [%d] %s', [Diag.Code, Diag.Message]));
xlsDiagnosticError:
begin
Writeln(Format('ERROR [%d] %s (sheet %s, native %d)',
[Diag.Code, Diag.Message, Diag.SheetName, Diag.NativeCode]));
Inc(FailedSheetCount);
end;
xlsDiagnosticFatal:
raise Exception.CreateFmt('Fatal HotXLS diagnostic %d: %s', [Diag.Code, Diag.Message]);
end;
end;
OnDiagnostic'i bir toplu iş hattına bağlamak
Diagnostics'i her çağrıdan sonra sorgulamak tek bir dosya için işe yarar; on binlik gece toplu işine geri döndüğünüzde işe yaramaz olur, çünkü Diagnostics her Open, SaveAs ve Recalculate çağrısının başında temizlenir. Bir döngüde üçüncü dosyadan sonra okuyun ve yalnızca üçüncü dosyanın tanılamalarını görürsünüz; ilk iki dosyanın bildirdiği her ne ise zaten gitmiştir. OnDiagnostic, koleksiyonu bir akışa dönüştürerek bunu çözer: döngü başlamadan önce bir kez abone olun ve dosya adı bir örnek alanı üzerinden kapsamda kalırken aynı işleyici sırayla her dosya için tetiklenir
type
TBatchConverter = class
private
FCurrentFile: string;
FFailedFiles: TStringList;
procedure HandleDiagnostic(Sender: TObject; Diagnostic: TXLSDiagnostic);
end;
procedure TBatchConverter.HandleDiagnostic(Sender: TObject; Diagnostic: TXLSDiagnostic);
begin
if Diagnostic.Severity >= xlsDiagnosticError then
FFailedFiles.Add(Format('%s: [%d] %s (sheet %s)',
[FCurrentFile, Diagnostic.Code, Diagnostic.Message, Diagnostic.SheetName]));
end;
// inside the batch loop:
Book.OnDiagnostic := HandleDiagnostic;
for I := 0 to FileNames.Count - 1 do
begin
FCurrentFile := FileNames[I];
if Book.Open(FCurrentFile) = 1 then
Book.SaveAs(ChangeFileExt(FCurrentFile, '.xlsx'));
end;
Geri çağırma gerçekte neye mal olur?
OnDiagnostic yapısal bir nedenden dolayı ucuzdur: yalnızca bir şey zaten yanlış gittiğinde tetiklenir ve yanlış olan, bir çalışma kitabının tuttuğu hücre, satır veya çalışma sayfası sayısına kıyasla nadirdir. Bunu, rutin ilerlemeyi bildiren ve en baştan çağrı sıklığı etrafında tasarlanmak zorunda olan OnProgress ve OnProgressEx ile karşılaştırın. HotXLS, Open ve SaveAs sırasında sayfa düzeyinde ilerlemeyi hücre veya satır başına değil sayfa başına bir kez tetikler; bu, milyonlarca hücreli çalışma kitaplarında bile çağrı başına ek yükü küçük tutan şeydir. Recalculate daha da ileri gider ve kendi ilerleme olayını bağımlılık grafiğinin yaklaşık her yüzde dördünde bir kısıtlar; bu yüzden tam bir yeniden hesaplama size bir kalp atışı verir, UI iş parçacığınızı olaylarla boğmak yerine. Tanılama hiç bu kısıtlamaya ihtiyaç duymadı, çünkü olay sayısı dosyanın boyutuyla değil gerçek sorunların sayısıyla sınırlıdır
Performansın hâlâ size bağlı olduğu tek yer işleyicinin kendisidir. OnDiagnostic, Open, SaveAs veya Recalculate'i çalıştıran iş parçacığında eşzamanlı olarak tetiklenir; bu yüzden bloke olan bir işleyici -örneğin uzak bir günlükleme servisine eşzamanlı bir yazma- o çağrının duvar saati süresinin bir parçası haline gelir. Tek bir dosya için bu görünmezdir. On bin dosyalık bir toplu iş üzerinde çarpıldığında ise bu, gece bitecek bir iş ile öğlen hâlâ çalışıyor olan bir iş arasındaki farktır; bu yüzden işleyicinin yapması gerekeni arabelleğe alın ve yavaş kısmı satır içinde yapmak yerine eşzamansız olarak boşaltın
Yapılandırılmış tanılama, tam olarak boolean bir sonucun en zayıf olduğu yerde, tek bir dosya yerine birçok dosyaya dokunan iş akışlarında en değerlidir. Bir çalışma kitabı denetimi ve dönüştürme hattı en açık örnektir: dosya başına çıplak bir geçti/kaldı kaydetmek yerine, her dosyanın Diagnostics listesini denetim kaydına ekleyin ve rapor size yalnızca neyin başarısız olduğunu değil nedenini de söyler ki bu, bir çalışma kitabı denetimi ve dönüştürme çalışma tezgahı kurma üzerine makalemizin en başından itibaren doğru yapmaya çalıştığı şeyin büyük kısmıdır. İlerleme ve tanılamanın aynı eşleşmesi, kendi başına zaten ilerleme raporlaması gerektiren herhangi bir iş akışına da aittir ki bu tam olarak HotXLS'te büyük çalışma kitabı performansı rehberimizde ele alınan alandır; burada uzun bir Open veya SaveAs çağrısı, OnProgress'in zaten bağlı olduğu ve OnDiagnostic'in yanına doğal, neredeyse bedava bir ekleme olduğu kadar yaygındır
Bunların hiçbiri hatta Excel'in kurulu olmasını gerektirmez ve hiçbiri genel bir istisnayı yakalayıp ne anlama geldiğini tahmin etmenizi gerektirmez. IXLSWorkbookProgress ve onun Diagnostics, LastDiagnostic ve OnDiagnostic üyeleri, Delphi ve C++Builder için HotXLS Bileşeni'nin standart yüzeyinin parçasıdır; tam tanılama kodu referansının ve bu makalenin ele aldığı geri kalan Open, SaveAs ve Recalculate yüzeyinin yanında