HotXLS .xls, .xlsx, .xlsm, .ods, CSV ve TSV kaynaklarını tek bir çekme satır imleci olan TXLSRowCursor aracılığıyla okur; imlecin FindFirst ve FindNext yordamları her çağrıda bir mantıksal satır ilerler ve yalnızca o satır bellekte kalır. Altı değerli bir durum makinesi, ilk-öncesi durumunu EOF, iptal edilen ve hatalı olandan ayırır; eski geri çağrım okuyucu artık aynı imlecin üzerinde bir bağdaştırıcıdır
Bu senaryo, bir içe aktarım özelliği sunmuş herkese tanıdıktır. 200 MB boyutunda bir .xlsx gelir, bir OnCell işleyicisi bağlarsınız ve "oku" isteğinden sonraki ilk gereksinim "ters çevrilen ilk yüz kayıttan sonra dur" olur. Artık kodunuzun biçimi size karşı savaşır: döngü kitaplığın içindedir, işleyicinizin bir bayrak yükseltmesi gerekir, ayrıştırıcı fark edene kadar sonraki her geri çağrım yine tetiklenir ve biriken durum — şimdiye kadar kaç eşleşme, hangi sütun eşleşti, sırada ne yapmalı — yalnızca geri çağrıma oturacak bir yer vermek için var olan bir sınıfın alanlarında yaşamak zorundadır. Bunların hiçbiri bir ayrıştırma sorunu değildir. Bu bir denetim akışı sorunudur ve çekme imlecinin ortadan kaldırdığı şey de budur
200 MB boyutunda bir gönderme geri çağrımının gerçek maliyeti nedir?
Gönderme denetimi tersine çevirir ve tersine çevirme, tam olarak filtreleyen ya da birleştiren bir çağıranın karşılayamayacağı şeydir. Geri çağrım API ile döngünün sahibi kitaplıktır; bu yüzden çağıran Break kullanamaz, iki kaynağı araya seremez, okuyucuyu sürülmeyi bekleyen bir yordama veremez ve "karar vermeden önce sonraki satıra göz at" isteğini arabellekleme olmadan ifade edemez. Maliyet aktarım hızı değildir — iyi yazılmış bir SAX geri çağrım yolu akışı sorunsuz yapar — maliyet, önemsiz olmayan her tüketicinin, yazmasına izin verilmeyen döngüyü taklit etmek için kendi küçük durum makinesini büyütmesidir. Bunu, her biri tarihsel olarak kendi tarama giriş noktasına sahip dört dosya biçimiyle çarpın; filtreleme, formül ve hata semantiği aralarında ayrışmaya başlar ve HotXLSin kapatmak için yola çıktığı kayma tam olarak budur
Çekme imleci çağıran kodunuzu nasıl değiştirir?
Döngüyü size geri verir ve onunla birlikte sıradan Pascal denetim akışını. TXLSRowCursor.Open bir dosya adı ya da bir TStream kabul eder, biçimi algılar, paylaşılan dizgeleri ve tarih stili meta verilerini bir kez yükler ve 1. sayfayı seçer. SelectSheet (1 tabanlı) ya da SelectSheetByName başka bir çalışma sayfasına yeniden hedefler ve imleci ilk-öncesi durumuna sıfırlar. FindFirst ve FindNext bundan sonra bir sonraki dolu satıra konumlanır — çözülebilir hücresi olmayan satırlar atlanır, bu yüzden RowIndex sıçrayabilir — ve geçerli satır CellCount, Cells[] ve ValueByCol[] olarak sunulur; hepsi sütun ekseninde 1 tabanlıdır. Döngüden çıkmak bir Break olur
var
Cursor: TXLSRowCursor;
Hits: Integer;
begin
Cursor := TXLSRowCursor.Create;
try
Cursor.FirstRow := 2; // başlık bandını atla
Cursor.IncludeColumn(1); // yalnızca bu iki sütunu çöz
Cursor.IncludeColumn(7);
if not Cursor.Open('postings-200mb.xlsx') then
Exit;
if not Cursor.SelectSheetByName('Ledger') then
Exit;
Hits := 0;
if Cursor.FindFirst then
repeat
if VarToStr(Cursor.ValueByCol[7]) = 'REVERSED' then
begin
Inc(Hits);
if Hits = 100 then
Break; // sıradan Break; iptal bayrağı yok, nöbetçi yok
end;
until not Cursor.FindNext;
finally
Cursor.Free; // yıkıcı geçişi sonlandırır
end;
end;
İzdüşüm ve aralık geçişten önce ayarlanır, sonradan filtrelenmez. FirstRow, LastRow, IncludeColumn, ClearColumnProjection, IncludeFormulaText, DetectDates ve DetectTextTypes seçeneklerinin hepsi arka uçların içinde onurlandırılır; bu yüzden seçilmemiş bir sütun hiçbir zaman değerini, formül dizgesini ya da zengin metin yükünü en başta ayırmaz — regresyon paketi bunu 16 KiB boyutundaki formüllerle ve sütunları izdüşümlenmediğinde hiçbir zaman maddeselleştirilmeyen önbellekli dizgelerle kanıtlar. Bu seçenekler bir geçiş etkinken bilinçli olarak dondurulur ve EOF noktasında, SelectSheet üzerinde ya da Close sonrasında yeniden yazılabilir hale gelir; böylece tek bir tarama asla iki çözümleme sözleşmesini karıştıramaz. Satırlar yerine yalnızca sayfa envanterine gereksiniminiz varsa, yalnızca meta veri ve seçici sayfa yükleme daha ucuz giriş noktasıdır
Biçim başına bir arka uç, her birine bir tarama döngüsü
HotXLS içinde her biçimin tam olarak bir ileri tarayıcısı vardır ve hem çekme imleci hem de geri çağrım okuyucu aynı tarayıcıyı sürer. TXLSXForwardRowBackend, ECMA-376 Part 1 §18.3 sayfa bölümleri için tek çalışma sayfası SAX durum makinesidir; XML okuyucuyu, paylaşılan formül tablosunu ve zengin metin ayrıştırıcısını tutar ve çağrı başına tam olarak bir fiziksel <row> sınırına ilerler. TXLSBiffForwardParser, [MS-XLS] kayıt akışı için genel verilerin, sayfa seçiminin ve satır ilerletmesinin sahibidir; onu duraklatılabilir yapmak tüm tasarımın en keskin kısıtını doğurdu, çünkü önbellekli dizge formülü, hemen ardından bir String kaydının geldiği bir Formula kaydıdır; bu yüzden satır başı askı noktası asla ikisinin arasına düşmemelidir. TXLSForwardTextBackend BOM farkında bir okuyucu, etkin ayraç ve bir mantıksal kayıt tutar — CSV ilk kayıttan virgül, noktalı virgül, sekme ya da dikey çubuğu tırnak içi karakterleri yok sayarak sezer ve çok satırlı tırnaklı alanlar #10 ile birleştirilir, böylece satır numarası fiziksel yeni satırlar yerine mantıksal kayıtları izler. TXLSForwardOdsBackend OpenDocument §9 tabloları için tek bir fiziksel satır kalıbı tutar, table:number-rows-repeated değerini bir genişletme yerine kalan sayı olarak ele alır ve kapsanan hücreleri değer yaymadan geçer. Akışlı doğrudan okuyucu aynı paylaşılan dizge ve tarih stili yükleyicisini paylaşır
Neden tek bir Eof bayrağı yerine altı durum?
Çünkü tek bir boole değeri dört farklı durumu birbirinden ayırt edilemez kılar ve çağıranlar hepsi hakkında yanlış tahmin yürütür. TXLSRowCursorState bunları açıkça adlandırır
xrcsClosed— açık kaynak yokxrcsBeforeFirst— açıldı ya da yeniden hedeflendi, henüz satır okunmadıxrcsActive— geçerli bir satır üzerinde duruyorxrcsEof— sayfa sonuna kadar tüketildixrcsCancelled— çağıran geçişi bilinçli olarak durdurduxrcsFaulted— geçiş başarısız oldu ve özgün özel durum yükseltildi
Üretimde önemli olan son ayrımdır. Eksik bir çalışma sayfası bölümü ya da başarısız bir geçiş başlangıcı EReadError hatasını korur ve imleci xrcsFaulted durumuna taşır; asla bir çağıranın "bu sayfa boştu" diye okuyacağı düz bir False değerine indirgenmez. Cancel, bilinçli olarak Close işlevinden daha dardır: geçerli çalışma sayfası arka ucunu ve onun açma alt akışını kapatır ve geçerli satırı geçersiz kılar, ancak ZIP arşivini ya da kaynak akışı bırakmaz ve onu iki kez çağırmak etkisiz bir işlemdir. İptalden sonra açıkça SelectSheet çağırarak devam edersiniz — imleç sizin adınıza sessizce bir geçişi yeniden başlatmaz. Akış sahipliği aynı savunmacı kuralı izler: xsoBorrowed varsayılandır ve kapanışta akış konumunu geri yükler; xsoOwned ise sahipliği ancak Open zaten başardıktan sonra devreder, böylece başarısız bir açılış çağıranın hâlâ tuttuğu bir akışı asla serbest bırakmaz
var
Cursor: TXLSRowCursor;
Src: TFileStream;
begin
Src := TFileStream.Create('quarter.ods', fmOpenRead or fmShareDenyWrite);
try
Cursor := TXLSRowCursor.Create;
try
// xsoBorrowed: imleç Src akışını asla serbest bırakmaz ve Close, Open
// çağrıldığında akışın sahip olduğu konumu geri yükler
if not Cursor.Open(Src, xffAuto, xsoBorrowed) then
Exit;
if Cursor.FindFirst then
repeat
if UserPressedStop then
begin
Cursor.Cancel; // çalışma sayfası arka ucunu ve onun açma
Break; // alt akışını kapatır; idempotent
end;
until not Cursor.FindNext;
case Cursor.State of
xrcsEof: Log('sheet consumed to the end');
xrcsCancelled: Log('stopped by the operator');
xrcsFaulted: Log('pass failed; the EReadError was already raised');
end;
finally
Cursor.Free;
end;
finally
Src.Free; // hâlâ bizim, hâlâ geçerli, konum geri yüklendi
end;
end;
Geçerli satırı kopyalamadan ödünç almak
IXLSRowCursorView bir satırı hücre dizisini çoğaltmadan başka bir yordama verir. Görünüm, imleç işaretçisini tutan paylaşılan bir koruyucu ile bir UInt64 nesil sayacı depolar; ilerletmek, sayfa seçmek, iptal etmek, kapatmak ve imleci yıkmak o nesli hep artırır ve yıkım ayrıca koruyucu sahibini temizler. Böylece bayat bir görünüm boşaltılmış belleği okuyamaz: Valid, istediğiniz zaman çağırabileceğiniz özel durum üretmeyen bir yoklamadır; diğer her üye ise önce doğrular ve EXLSRowCursorViewInvalidated hatasını yükseltir. Bu sözleşmenin ne olduğu konusunda dürüst olun — bu yaşam süresi hızlı başarısızlığıdır, bir iş parçacığı güvenliği garantisi değildir ve birinci iş parçacığı imleci ilerletirken ikinci bir iş parçacığından satır okumaya izin vermez
var
View: IXLSRowCursorView;
Cell: TXLSRowCursorCell;
I: Integer;
begin
if Cursor.FindFirst then
repeat
View := Cursor.CurrentRowView; // ödünç alır; hiçbir hücre dizisi kopyalanmaz
for I := 0 to View.CellCount - 1 do
begin
Cell := View.Cells[I];
if Cell.HasFormula and not Cell.FormulaTextAvailable then
UseCachedResult(Cell.Value) // BIFF ileri okumaları belirteçleri değil
else if Cell.Kind = xdkEmpty then // önbelleğe alınmış sonucu tutar
UseStyleOnly(Cell.StyleIndex) // Blank / MulBlank gerçek hücrelerdir
else
UseValue(Cell.Col, Cell.Value);
end;
until not Cursor.FindNext;
// Arabirim döngüden uzun yaşar ama ardındaki satır yaşamaz
if not View.Valid then // Valid asla hata vermez; Cells[] şimdi verirdi
View := nil; // EXLSRowCursorViewInvalidated
end;
PeakRowBufferedBytes ve kanıtlamasına izin verilen şey
PeakRowBufferedBytes, belleğin satır sayısını değil satır genişliğini izlediğini göstermek için vardır. Geçerli çıktı satırının hücre kayıtlarını, Variant değerlerini, formül dizgelerini ve zengin metin yüklerini biriktirir ve biçime özgü çalışma kümesini katlar — CSV mantıksal kaydı, ODS fiziksel satır kalıbı, BIFF kayıt tepe değeri ya da çözümlenmekte olan XLSX ham hücresi. Bunu, kaç çalışma sayfası geçişinin gerçekten başladığını sayan SheetPassesStarted ile birlikte okuyun. İki uyarı bunu dürüst tutar: rakam kesin yığın muhasebesi değil bir tahmindir ve en son Open işleminden beri monotondur; bu yüzden canlı bir ölçü aleti yerine bir hata ayıklama ve regresyon aracıdır. Çok büyük kitaplarda zamanın ve baytların nereye gittiğine ilişkin geniş tablo için Delphi ile büyük çalışma kitabı performansına bakın
Gönderme okuyucu bir bağdaştırıcıya dönüştü ve imlecin yapmayacağı şeyler
TXLSForwardReader artık ayrı XLSX, BIFF ve metin tarama giriş noktaları taşımaz. Bir imleç yapılandırır, onu yürütür ve geçerli satırı OnSheet ve OnCell olaylarına çevirir; iki cephenin filtreleme, formül durumu ya da hata işleme konusunda artık ayrışamamasının nedeni budur. Yükseltmeden önce bilinmeye değer iki sonuç var: geri çağrım SheetIndex değeri TXLSForwardReader üzerinde artık tutarlı biçimde 1 tabanlıdır (TXLSDirectReader mevcut 0 tabanlı olay sözleşmesini korur) ve OnSheet olayı SelectSheet işlevinden önce tetiklenir; bu yüzden SkipSheet ayarlamak, çalışma sayfası bölümünün hiç açılmaması ya da hiç sıkıştırılmaması anlamına gelir. Sınırlar aynı ölçüde açıktır: bir geçiş etkinken çalışma kitabı değiştirilmemelidir, iptal açık bir yeniden başlatma gerektirir ve BIFF ileri yolu formül belirteçlerinin derlemesini asla açmaz; bu yüzden klasik formül hücreleri HasFormula değerini True, FormulaTextAvailable değerini False bildirir ve boş bir formül dizgesi icat etmek yerine önbelleğe alınmış sonucu size verir. Satır imleci ve bağdaştırıcısı, Delphi Win32 ve Win64 üzerinde 1.298 denetimi ve buna ek olarak C++Builder 37.0 Win64 statik paketini geçti
Bir çekme imlecini şu anda sahip olduğunuz yükleyiciyle tartıyorsanız, sorulacak soru hangisinin daha hızlı ayrıştırdığı değil, hangisinin gerçekten gereksinim duyduğunuz çıkış koşulunu yazmanıza izin verdiğidir. Tüm bileşen ayrıntıları, desteklenen IDE sürümleri ve lisanslama HotXLS Delphi elektronik tablo bileşeni sayfasında yer alır