HotXLS membuka workbook yang ditulis Excel 2.0, 3.0, dan 4.0 langsung dari Delphi dan C++Builder. Berkas-berkas ini mendahului container OLE compound document yang digunakan setiap .xls generasi setelahnya, sehingga berkas tersebut adalah stream rekaman BIFF mentah tanpa wrapper storage sama sekali, dan pembaca yang dibangun untuk BIFF8 tidak akan menemukan satu pun struktur yang dikenalinya di dalamnya. Membuka salah satunya menggunakan panggilan Open yang sama seperti workbook lainnya; pembaca mendeteksi formatnya dan berpindah jalur
Berkas-berkas ini masih muncul, dan itulah satu-satunya alasan mengapa semua ini penting. Arsip rekayasa, retensi catatan pemerintah, data laboratorium dari instrumen yang perangkat lunak kontrolnya ditulis tahun 1993, dan sistem akuntansi yang berjalan lama semuanya meninggalkan workbook BIFF2 dan BIFF4. Excel modern menolak membuka beberapa di antaranya secara langsung, karena telah menghapus converter lawas demi alasan keamanan, yang meninggalkan sekumpulan data yang tidak dapat dibaca siapa pun dengan alat yang dimiliki siapa pun
Apa yang membuat workbook pra-OLE berbeda?
Setiap .xls dari Excel 5.0 dan seterusnya adalah compound file OLE2, sebuah sistem berkas kecil di dalam sebuah berkas, dengan workbook berada dalam stream bernama Workbook atau Book. Mem-parsing salah satunya dimulai dengan mem-parsing container itu, seperti dijelaskan dalam format biner compound file dalam Pascal
BIFF2 hingga BIFF4 tidak memiliki container. Berkas langsung dimulai dengan rekaman BOF, dan nomor rekaman BOF itu menyandikan generasinya: $0009 untuk BIFF2, $0209 untuk BIFF3, dan $0409 untuk BIFF4. HotXLS memvalidasi panjang body BOF, yang berkisar antara empat hingga enam byte, dan tipe substream, $0010 untuk worksheet, $0020 untuk chart, dan $0040 untuk macro sheet, sebelum berkomitmen pada jalur mentah. Validasi itulah yang mencegah berkas yang korup atau salah diidentifikasi diinterpretasikan sebagai workbook yang sangat lawas
Tiga generasi, tiga layout rekaman
Rekaman cell adalah tempat generasi-generasi ini paling nyata berbeda. BIFF2 menempati blok berkelanjutan nomor rekaman rendah, $0001 hingga $0005 untuk cell blank, integer, number, label, dan boolean-or-error, dan setiap body-nya membawa field atribut tiga byte tempat versi belakangan menaruh indeks extended format. BIFF3 dan BIFF4 meninggalkan itu dan menggunakan kembali nomor rekaman dan layout BIFF5, $0201, $0203, $0204, dan $0205, dengan indeks XF dua byte
Detail terakhir itu menyebabkan kegagalan spesifik yang mudah salah didiagnosis. Rekaman LABEL BIFF3 atau BIFF4 secara struktural identik dengan padanan BIFF5-nya, baris dan kolom diikuti indeks format lalu jumlah karakter. Tulis pembaca yang mengasumsikan layout BIFF2 dan ia akan membaca dua byte terlalu sedikit, lalu melenceng melewati akhir rekaman dan salah menginterpretasikan segala sesuatu sesudahnya. Gejalanya bukan sebuah exception; melainkan workbook yang terbaca dengan sampah yang tampak masuk akal di dalamnya
Rekaman formula menempati penomoran paralel di ketiganya, $0006, $0206, dan $0406. Ketika sebuah formula menghasilkan hasil string, string itu tiba dalam rekaman terpisah yang mengikutinya, $0007 atau $0207, dan bentuk BIFF2-nya menggunakan prefix panjang satu byte alih-alih yang dua byte yang digunakan belakangan
Mengapa formula kembali sebagai value, bukan sebagai teks?
HotXLS membaca hasil cache dari sebuah formula dalam berkas-berkas ini dan tidak berusaha merekonstruksi ekspresi formulanya. Ini adalah batasan yang disengaja, bukan celah yang menunggu diisi
Ekspresi yang di-parsing dalam BIFF2 hingga BIFF4 menggunakan pengkodean token yang berbeda dari BIFF5 dan generasi setelahnya dengan cara yang melampaui hal kosmetik: panjang token diberi prefix secara berbeda, token referensi memiliki ukuran berbeda, dan tabel indeks fungsi dinomori ulang antar generasi. Menjalankan byte-byte itu melalui translator ekspresi BIFF8 tidak menghasilkan formula yang salah, ia menghasilkan formula yang acak. Membaca value tercache memberi Anda angka atau string yang terakhir dihitung Excel, yang memang dibutuhkan migrasi arsip
Value tercache berada pada offset yang bergantung generasi di dalam rekaman: byte 7 untuk BIFF2 dan byte 6 untuk BIFF3 dan BIFF4. Value khusus, string, boolean, error, dan blank, disandikan dalam marker word $FFFF dengan diskriminator, konvensi yang sama yang dipertahankan generasi BIFF berikutnya
Membuka salah satunya
Kode pemanggilnya tidak istimewa, dan itulah maksudnya. Deteksi terjadi di dalam Open:
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[] berbasis 1
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;
Perhatikan aritmetika indeks dalam loop tersebut. Batas UsedRange berbasis nol sementara koleksi sheet dan akses cell keduanya berbasis satu, sebuah inkonsistensi yang mendahului API saat ini dan dipertahankan demi kompatibilitas. Melupakan penyesuaian itu akan mengaudit persegi panjang yang salah dan tidak melaporkan apa pun yang tidak biasa sambil melakukannya. Pemeriksaan awal murah yang menghindari pemuatan berkas sama sekali dibahas dalam inspeksi workbook ringan
Apa yang tidak Anda dapatkan, dan apa yang harus dilakukan soal itu
Pemformatan tidak diinterpretasikan. HotXLS tidak mem-parsing rekaman XF dan FONT dari generasi-generasi ini, sehingga font, warna, border, dan format angka tidak tersedia, dan cell yang dulu ditampilkan Excel sebagai tanggal kembali sebagai nomor serial mentahnya
Hal terakhir itu perlu ditangani dalam kode Anda sendiri, bukan dalam pembaca, dan alasannya jujur: format angka dalam BIFF2 hingga BIFF4 tidak cukup andal untuk menggerakkan keputusan tanggal otomatis. Sebuah kolom berisi angka lima digit bisa jadi tanggal, atau bisa jadi nomor bagian. Konversilah dengan sengaja, menggunakan sistem tanggal workbook, yang aturannya dijelaskan dalam nomor serial tanggal, sistem 1904, dan format angka:
// Putuskan per kolom, jangan pernah per nilai: angka lima digit bisa
// berupa tanggal atau nomor bagian, dan format lawas tidak akan memberitahu Anda
if ColumnHoldsDates(C) then
begin
// Kedua sistem tanggal berjarak 1462 hari, sehingga serial yang sama
// menyatakan dua tanggal yang berjarak empat tahun. Baca sistemnya dari
// workbook, jangan mengasumsikan satu sistem
if Book.Date1904 then
Writeln(DateToStr(SerialToDate1904(V)))
else
Writeln(DateToStr(SerialToDate1900(V)));
end
else
Writeln(VarToStr(V));
Dua catatan struktural melengkapi gambarannya. Perlindungan kata sandi dan rekaman code page muncul di dalam stream worksheet tunggal alih-alih dalam stream level workbook, karena tidak ada stream level workbook untuk menempatkannya, sehingga keduanya harus dikenali dalam konteks worksheet. Dan berkas BIFF2 hingga BIFF4 mengandung tepat satu substream sheet; workbook multi-sheet belum ada sampai format ini mendapatkan container-nya
Jalur migrasi yang pragmatis karena itu adalah dua langkah: baca berkas lawas untuk value-nya, lalu tulis workbook modern yang membawa value tersebut dengan pemformatan yang Anda terapkan sendiri. Pembacaan lawas, penulisan modern, dan segala sesuatu di antaranya berjalan dalam satu library untuk Delphi dan C++Builder, dijelaskan pada halaman komponen spreadsheet Delphi HotXLS