HotXLS, Excel 2.0, 3.0 ve 4.0 tarafından yazılan çalışma kitaplarını doğrudan Delphi ve C++Builder'dan açar. Bu dosyalar, sonraki her .xls dosyasının kullandığı OLE bileşik belge kapsayıcısından öncesine aittir, bu yüzden hiçbir depolama sarmalayıcısı (wrapper) olmayan ham BIFF kayıt akışlarıdır ve BIFF8 için oluşturulmuş bir okuyucu içlerinde tanınabilir tek bir yapı bulamaz. Birini açmak, diğer herhangi bir çalışma kitabıyla aynı Open çağrısını kullanır; okuyucu biçimi algılar ve yol değiştirir
Bu dosyalar hâlâ karşımıza çıkıyor ve tüm bunların önemli olmasının tek nedeni bu. Mühendislik arşivleri, devlet kayıt saklama gereksinimleri, kontrol yazılımı 1993'te yazılmış cihazlardan gelen laboratuvar verileri ve uzun süredir çalışan muhasebe sistemlerinin hepsi geride BIFF2 ve BIFF4 çalışma kitapları bıraktı. Modern Excel, güvenlik nedenleriyle eski dönüştürücüleri kaldırdığından, bunların birçoğunu doğrudan açmayı reddediyor; bu da kimsenin elindeki bir araçla okuyamayacağı bir veri kümesi bırakıyor
OLE öncesi bir çalışma kitabını farklı kılan nedir?
Excel 5.0'dan itibaren her .xls dosyası, bir dosya içindeki küçük bir dosya sistemi olan bir OLE2 bileşik dosyasıdır; çalışma kitabı, Workbook veya Book adlı bir akışta yaşar. Birini ayrıştırmak, Pascal'da bileşik dosya ikili biçimi yazısında anlatıldığı gibi o kapsayıcıyı ayrıştırmakla başlar
BIFF2'den BIFF4'e kadar hiçbir kapsayıcı yoktur. Dosya doğrudan bir BOF kaydıyla başlar ve bu BOF'un kayıt numarası kuşağı kodlar: BIFF2 için $0009, BIFF3 için $0209 ve BIFF4 için $0409. HotXLS, ham yola bağlanmadan önce, dört ile altı bayt arasında olan BOF gövde uzunluğunu ve alt akış türünü — bir çalışma sayfası için $0010, bir grafik için $0020 ve bir makro sayfası için $0040 — doğrular. Bu doğrulama, bozuk veya yanlış tanımlanmış bir dosyanın çok eski bir çalışma kitabı olarak yorumlanmasını önleyen şeydir
Üç kuşak, üç kayıt düzeni
Hücre kayıtları, kuşakların en görünür biçimde ayrıştığı yerdir. BIFF2, boş, tam sayı, sayı, etiket ve boolean-veya-hata hücreleri için $0001'den $0005'e kadar düşük kayıt numaralarından oluşan bitişik bir blok kaplar ve her gövde, sonraki sürümlerin genişletilmiş bir biçem indeksi koyduğu yerde üç baytlık bir öznitelik alanı taşır. BIFF3 ve BIFF4 bunu terk eder ve BIFF5 kayıt numaralarını ve düzenlerini — $0201, $0203, $0204 ve $0205'i — iki baytlık bir XF indeksiyle yeniden kullanır
Bu son ayrıntı, belirli ve kolayca yanlış teşhis edilen bir hataya yol açar. Bir BIFF3 veya BIFF4 LABEL kaydı, yapısal olarak BIFF5 karşılığıyla özdeştir: satır ve sütun, ardından biçem indeksi ve ardından karakter sayısı. BIFF2 düzenini varsayan bir okuyucu yazın, iki bayt eksik okur, ardından kaydın sonundan taşar ve sonrasındaki her şeyi yanlış yorumlar. Belirti bir istisna değildir; içinde makul görünen çöp veriyle okunan bir çalışma kitabıdır
Formül kayıtları, üçünde de paralel bir numaralandırma kaplar: $0006, $0206 ve $0406. Bir formül bir dize sonucu ürettiğinde, o dize ayrı, sonraki bir kayıtta gelir — $0007 veya $0207 — ve bunun BIFF2 biçimi, daha sonra kullanılan iki baytlık önek yerine tek baytlık bir uzunluk öneki kullanır
Formüller neden metin olarak değil değer olarak geri döner?
HotXLS, bu dosyalardaki bir formülün önbelleğe alınmış sonucunu okur ve formül ifadesini yeniden oluşturmaya çalışmaz. Bu, doldurulmayı bekleyen bir eksiklik değil, bilinçli bir sınırdır
BIFF2'den BIFF4'e kadar olan ayrıştırılmış ifade, BIFF5 ve sonrasından kozmetik farklılıkları aşan bir belirteç (token) kodlaması kullanır: belirteç uzunlukları farklı önceklenir, referans belirteçlerinin boyutları farklıdır ve fonksiyon indeksi tabloları kuşaklar arasında yeniden numaralandırılmıştır. Bu baytları bir BIFF8 ifade çevirmeninden geçirmek yanlış bir formül üretmez, rastgele bir formül üretir. Önbelleğe alınmış değeri okumak, size Excel'in son hesapladığı sayıyı veya dizeyi verir; bir arşiv geçişinin gerçekten ihtiyaç duyduğu şey de budur
Önbelleğe alınmış değer, kayıt içinde kuşağa bağlı bir konumda (offset) yaşar: BIFF2 için 7. bayt, BIFF3 ve BIFF4 için 6. bayt. Özel değerler — dizeler, boolean'lar, hatalar ve boşluklar — bir ayırt edici (discriminator) ile birlikte $FFFF işaretçi sözcüğünde kodlanır; sonraki BIFF kuşaklarının koruduğu aynı kural
Bir dosya açmak
Çağıran kod sıradandır ve mesele de budur. Algılama Open içinde gerçekleşir:
uses
lxHandle;
var
Book: TXLSWorkbook;
Sheet: TXLSWorksheet;
R, C: Integer;
V: Variant;
begin
Book := TXLSWorkbook.Create;
try
if Book.Open('archive\1993-inventory.xls') <> 1 then
begin
Writeln('unreadable - quarantine for manual review');
Exit;
end;
Sheet := Book.Sheets[1]; // Sheets[] bir tabanlıdır
for R := Sheet.UsedRange.FirstRow + 1 to Sheet.UsedRange.LastRow + 1 do
for C := Sheet.UsedRange.FirstCol + 1 to Sheet.UsedRange.LastCol + 1 do
begin
V := Sheet.Cells[R, C].Value;
if not VarIsEmpty(V) then
Writeln(Format('R%dC%d = %s', [R, C, VarToStr(V)]));
end;
finally
Book.Free;
end;
end;
O döngüdeki indeks aritmetiğine dikkat edin. UsedRange sınırları sıfır tabanlıyken hem sayfa koleksiyonu hem de hücre erişimi bir tabanlıdır; bu, mevcut API'den önceye ait ve uyumluluk için korunan bir tutarsızlıktır. Ayarlamayı unutmak, yanlış dikdörtgeni denetler ve bunu yaparken hiçbir olağandışı şey bildirmez. Bir dosyayı hiç yüklemeden yapılan ucuz ön kontroller, hafif çalışma kitabı incelemesi yazısında ele alınmıştır
Neyi elde etmezsiniz ve bu konuda ne yapmalı?
Biçimlendirme yorumlanmaz. HotXLS, bu kuşakların XF ve FONT kayıtlarını ayrıştırmaz, bu yüzden yazı tipleri, renkler, kenarlıklar ve sayı biçimleri kullanılamaz ve Excel'in bir zamanlar tarih olarak gösterdiği hücreler ham seri numaraları olarak geri döner
Sonuncusunun, okuyucuda değil kendi kodunuzda ele alınması gerekir ve nedeni dürüst: BIFF2'den BIFF4'e kadarki sayı biçimleri, otomatik bir tarih kararını yönlendirecek kadar güvenilir değildir. Beş basamaklı sayılardan oluşan bir sütun tarih olabilir veya parça numarası olabilir. Tarih seri numaraları, 1904 sistemi ve sayı biçimleri yazısında kuralları anlatılan çalışma kitabının tarih sistemini kullanarak bilinçli bir şekilde dönüştürün:
// Sütun başına karar verin, hiçbir zaman değer başına değil: beş basamaklı
// bir sayı tarih olabilir veya parça numarası olabilir, eski biçim size söylemez
if ColumnHoldsDates(C) then
begin
// İki tarih sistemi 1462 gün arayla ayrılır, bu yüzden aynı seri
// dört yıl arayla iki tarihi belirtir. Sistemi varsaymak yerine
// çalışma kitabından okuyun
if Book.Date1904 then
Writeln(DateToStr(SerialToDate1904(V)))
else
Writeln(DateToStr(SerialToDate1900(V)));
end
else
Writeln(VarToStr(V));
İki yapısal not tabloyu tamamlar. Parola koruması ve kod sayfası kayıtları, bir çalışma kitabı düzeyi akış yerine tek çalışma sayfası akışının içinde görünür, çünkü onları koyacak bir çalışma kitabı düzeyi akış yoktur, bu yüzden çalışma sayfası bağlamında tanınmaları gerekir. Ve BIFF2'den BIFF4'e bir dosya tam olarak bir sayfa alt akışı içerir; çok sayfalı çalışma kitapları, biçim kendi kapsayıcısını kazanana kadar var olmadı
Bu yüzden pragmatik geçiş yolu iki adımlıdır: eski dosyayı değerleri için okuyun, ardından bu değerleri kendinizin uyguladığı biçimlendirmeyle taşıyan modern bir çalışma kitabı yazın. Eski dosya okuma, modern yazma ve aradaki her şey, HotXLS Delphi elektronik tablo bileşeni sayfasında anlatılan Delphi ve C++Builder için tek bir kütüphanede çalışır