Bir giriş rutininin yanıt bulması gereken tek soru bazen yapısaldır: bu çalışma kitabında "Mapping" adlı bir sayfa var mı, ya da kaç sekme taşıyor. Bunu Open çağırarak yanıtlamak pahalı yoldur. Tam bir açma işlemi paylaşılan dizge tablosunu şişirir, her stil kaydını çözer ve her çalışma sayfasının hücrelerini dolaşır; çünkü yalnızca içindekiler listesini istediğinizi bilmesinin bir yolu yoktur. Büyük bir dosyada bu, birkaç kilobayt yer kaplayan bir listeyi okumak için yüzlerce megabaytlık bellek ayırma ve saniyelerce CPU demektir. losLab'ın yerel Delphi elektronik tablo kütüphanesi HotXLS bu listeyi tek başına verir: GetSheetNames, tek bir hücreyi bile somutlaştırmadan çalışma sayfası adlarını çalışma kitabı sırasıyla geri döndürür
Katalogu okumak neden ucuzdur
Her iki elektronik tablo biçimi de içindekiler listesini dosyanın başına yakın bir yere koyar; bir listeleme çağrısını zekice değil hızlı kılan şey budur. Bir OOXML paketi sayfa katalogunu xl/workbook.xml içinde tutar; bu parça, çalışma kitabı ister on satır ister on milyon satır barındırsın küçük kalır. BIFF8 bir .xls ise BoundSheet kayıtlarını, herhangi bir hücre verisinden önce, çalışma kitabı globals akışının başında saklar. Yani bir listeleme çağrısının kaçındığı iş, tam bir açma işlemine kıyasla yuvarlama hatası değildir. Dosyanın büyük bölümüdür. Katalogu okumak satır sayısından bağımsız olarak aynı birkaç kilobayta mal olur; tam açma ise veriyle birlikte ölçeklenir ve birkaç megabaytlık bir çalışma kitabında bu fark hem dokunulan bayt hem de ayrılan bellek açısından birkaç büyüklük mertebesine ulaşır
Tasarımı üzerine kurmaya değer özellik bu sabit maliyettir. GetSheetNames üzerine kurulmuş bir giriş kapısı 200 satırlık bir dosyada da 200 MB boyutundaki bir dosyada da aynı davranır; böylece bir yığındaki en yavaş dosya, bir dosyanın işlenmeye değer olup olmadığına karar verme hızını artık belirlemez
.xls, .xlsx ve şablon biçimleri için tek çağrı
XLS cephesinde TXLSWorkbook.GetSheetNames yalnızca .xls okumaz. Zip tabanlı .xlsx, .xlsm, .xltx ve .xltm dosyalarını da kabul eder ve arşivden yalnızca workbook.xml parçasını çeker. Gerçek .xls girdisi içinse BoundSheet kayıtlarını tarar ve globals alt akışının ilk EOF kaydında durur; böylece büyük bir ikili dosya bile yalnızca baştaki kilobaytları kadar maliyetlidir. XLSX cephesi, uzun ömürlü servis kodu için ilk bakışta göründüğünden daha önemli bir güvence taşır: TXLSXWorkbook.GetSheetNames çalışma kitabı örneğini ne sıfırlar ne de doldurur; dolayısıyla açık bir belgeyi tutan bir örnek, elindekini bozmadan başka dosyaları yoklayabilir. GetODSSheetNames aynı yaklaşımı OpenDocument paketlerine uygular ve bu çağrıların her birinin bir akış aşırı yüklemesi vardır; bu da diske hiç inmeyen bir yüklemeyi incelemenizi sağlar
var
Book: TXLSXWorkbook;
Names: TStringList;
I: Integer;
begin
Names := TStringList.Create;
Book := TXLSXWorkbook.Create;
try
if Book.GetSheetNames('upload-7f3a.xlsx', Names) <= 0 then
raise Exception.Create('unreadable workbook package');
if Names.IndexOf('Mapping') < 0 then
raise Exception.Create('required Mapping sheet is missing');
for I := 0 to Names.Count - 1 do
Writeln(Format('sheet %d: %s', [I, Names[I]]));
finally
Book.Free;
Names.Free;
end;
end;
Aynı çağrı iyi bir masaüstü içe aktarma iletişim kutusu da kurar. Sayfaları listeleyin, kullanıcının birini seçmesine izin verin ve tam açma bedelini ancak seçim yapıldıktan sonra ödeyin. Elli sayfalık bir çalışma kitabında fark gözle görülür: anında beliren bir seçici ile arkasında bütün dosya yüklenirken donan bir seçici
Makro etkin .xlsm dosyaları ve şablon biçimleri tıpkı düz bir .xlsx gibi listelenir; çünkü katalog, pakette bir vbaProject.bin bulunsun ya da bulunmasın aynı workbook.xml içinde durur. Bu nedenle bir giriş hattı, bir makro çalışma kitabının sayfalarını yönlendirme amacıyla sayabilir; makro yüküne hiç dokunmadan ve onu çalıştıracak hiçbir şey yapmadan, makro politikası kararını dosyayı gerçekten açan aşamaya bırakır
Dönüş değerini kendinizi kandırmadan okumak
Dönüş sözleşmeleri HotXLS genelinde tek biçimli değildir. Bazı çağrılar başarıda 1 döndürür, bazıları bir sayı döndürür; bu yüzden listeleme işlevlerinde ayakta kalan tek denetim, sıfır ve altındaki her değeri başarısızlık saymak ve dizge listesini temizlenmiş kabul etmektir. Boş bir listeyi "sayfası olmayan bir çalışma kitabı" diye okuma isteğine direnin. Hem ECMA-376 hem de BIFF8 belirtimi geçerli bir çalışma kitabında en az bir sayfa şartı koyar; dolayısıyla sıfır ad her zaman okumanın başarısız olduğu anlamına gelir, dosyanın meşru biçimde boş olduğu anlamına değil
Başarısız bir listeleme başlı başına saklamaya değer bir sinyaldir. Çağrıda başarısız olan bir .xlsx dosyası şu birkaç şeyden biridir: kırpılmış, aslında hiç OOXML paketi olmayan (başka sistemlerden gelen yanlış etiketlenmiş CSV çıktıları burada sürekli karşınıza çıkar) ya da şifreli bir kapsayıcı. Bunları birbirinden ayırmak bir sonraki denetimin işidir. Reddedilen dosyanın ilk baytlarını başarısızlıkla birlikte günlüğe yazmak, bir destek yazışmasını genelde tek mesaja indirir
Yönlendirmeden önce şifreli kapsayıcıları tespit etmek
Şifreli bir .xlsx zip değildir. EncryptionInfo ve EncryptedPackage akışlarını saran bir OLE bileşik dosyasıdır; bu yüzden GetSheetNames içini göremez ve okunamayan başka her dosyada olduğu gibi başarısızlık döndürür. CanReadEncrypted bu kapsayıcı biçimini sınar ve girişin, bir işçinin derinliklerinden gelen genel bir okuma hatasını yutmak yerine şifreli dosyayı bilinçli olarak yönlendirmesini sağlar:
type
TIntakeRoute = (irNormal, irNeedsPassword, irUnreadable);
function ClassifyUpload(const FileName: string; Names: TStrings): TIntakeRoute;
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// Şifreli OOXML bir zip değil, bir OLE kapsayıcısıdır: önce bunu
// denetleyin, çünkü listeleme çağrıları içine bakamaz.
if Book.CanReadEncrypted(FileName) then
Exit(irNeedsPassword);
if SameText(ExtractFileExt(FileName), '.ods') then
begin
if Book.GetODSSheetNames(FileName, Names) <= 0 then
Exit(irUnreadable);
end
else if Book.GetSheetNames(FileName, Names) <= 0 then
Exit(irUnreadable);
Result := irNormal;
finally
Book.Free;
end;
end;
HotXLS'in bilinçli olarak asimetrik davrandığı yer şifrelemedir ve yönlendirmenin buna saygı göstermesi gerekir. Eski .xls şifrelemesi (RC4, RC4 CryptoAPI, XOR) okunabilir: TXLSWorkbook.Open(FileName, Password) saklanan bir parolayla şifreyi çözer ve bu dosyalar otomatik yolda kalabilir. Şifreli OOXML paketleri ise tersine gider. HotXLS SaveAsEncrypted ile böyle bir paket yazabilir ama geri okuyamaz. OpenEncrypted, şifreli bir paket verildiğinde EXlsxEncryptionNotImplemented fırlatır; dürüst bir giriş tasarımının şifreli .xlsx dosyalarını Excel bulunan bir kişiye göndermesinin ve parola taşıyan .xls dosyalarını kodda tutmasının nedeni budur
Yığın işlerde bu sınıflandırıcı, herhangi bir işçi gerçek işleme başlamadan önce gelen dizinin tamamı üzerinde çalışarak yerini hak eder; çünkü her yoklama yaklaşık bir dosya açma ve birkaç kilobaytlık okuma kadar maliyetlidir. Bunu öne almak, operasyon ekibinin gerçekten önemsediği başarısızlık kipini değiştirir. Gece 3'te 600 dosyanın 412 numaralısında ölen bir iş yerine, girişte kuyruğa alınmış 412 dosya ve her birine bir gerekçe iliştirilmiş 5 ret elde edersiniz. Aynı kütüphane çağrıları, çok daha iyi bir operasyon hikâyesi
Bir listeleme çağrısının yanıtlayamadığı sorular
Elde ettiğinizin tamamı adlar ve sıradır. Listeleme çağrıları görünürlük hakkında hiçbir şey söylemez; gizli ve çok gizli sayfalar listeye diğerleriyle aynı görünümde gelir. Kullanılan aralık boyutlarını, hücre sayılarını ve belge özelliklerini bildirmezler. docProps/core.xml parçası da küçüktür ama bugün yalnızca özellikleri okuyan bir yoklama yoktur; bu yüzden yazar ve başlık meta verisi hâlâ tam bir Open maliyetindedir. Bununla yaşamanın temiz yolu, ucuz olguların her dosyayı yönlendirmesine izin vermek ve pahalı olanları yönlendirmeden sağ çıkan dosyalara ayırmaktır. Derin okumaya devam eden dosyalarda, büyük bir .xls dosyasının salt okunur taraması _DisableGraphics := True ile gözle görülür biçimde daha hızlı çalışır; bu ayar OfficeArt ayrıştırmasını atlar. Yalnızca o örnekten asla kayıt yapmayın: atladığı çizim katmanı modelde yoktur ve kaydetmek onu dosyadan düşürür
Triyajı geçen dosyalar genelde daha derin analize gider. Çalışma kitabı denetim ve dönüştürme tezgâhı, tam bir açma işlemi gerekçelendiğinde toplamaya değer sayfa başına sayaçları anlatır; büyük çalışma kitabı başarım rehberi ise bu tam açmayı hızlı tutmayı anlatır
HotXLS, Delphi ve C++Builder için yerel bir Object Pascal elektronik tablo kütüphanesidir; burada gösterilen inceleme çağrıları dahil olmak üzere eksiksiz API yüzeyi HotXLS Delphi Component ürün sayfasında belgelenmiştir