HotXLS avaa Excel 2.0:n, 3.0:n ja 4.0:n kirjoittamia työkirjoja suoraan Delphistä ja C++Builderista. Nämä tiedostot ovat vanhempia kuin OLE-yhdistelmädokumenttisäiliö, jota jokainen myöhempi .xls käyttää, joten ne ovat raakoja BIFF-tietuevirtoja ilman minkäänlaista säilykääretä, eikä BIFF8:aa varten rakennettu lukija löydä niiden sisältä yhtäkään tunnistettavaa rakennetta. Yhden avaaminen käyttää samaa Open-kutsua kuin mikä tahansa muu työkirja; lukija tunnistaa muodon ja vaihtaa polkua
Nämä tiedostot ilmestyvät edelleen, ja se on ainoa syy, miksi mikään tästä on merkityksellistä. Insinöörien arkistot, valtion asiakirjojen säilytys, laboratoriodata instrumenteista, joiden ohjausohjelmisto kirjoitettiin vuonna 1993, ja pitkään toimineet kirjanpitojärjestelmät jättivät kaikki jälkeensä BIFF2- ja BIFF4-työkirjoja. Nykyaikainen Excel kieltäytyy avaamasta useita niistä suoraan, koska se on poistanut vanhat muuntimet turvallisuussyistä, mikä jättää jälkeen tietoaineiston, jota kukaan ei voi lukea työkalulla, joka kenelläkään on
Mikä tekee OLE:a edeltävästä työkirjasta erilaisen?
Jokainen .xls-tiedosto Excel 5.0:sta lähtien on OLE2-yhdistelmätiedosto, pieni tiedostojärjestelmä tiedoston sisällä, jossa työkirja asuu virrassa nimeltä Workbook tai Book. Yhden jäsentäminen alkaa tuon säiliön jäsentämisellä, kuten kuvataan artikkelissa yhdistelmätiedoston binäärimuoto Pascalissa
BIFF2:sta BIFF4:ään ei ole säiliötä. Tiedosto alkaa välittömästi BOF-tietueella, ja tuon BOF:n tietuenumero koodaa sukupolven: $0009 BIFF2:lle, $0209 BIFF3:lle ja $0409 BIFF4:lle. HotXLS validoi BOF-rungon pituuden, joka on neljän ja kuuden tavun välillä, sekä alivirran tyypin, $0010 laskentataulukolle, $0020 kaaviolle ja $0040 makrotaulukolle, ennen kuin sitoutuu raakaan polkuun. Tämä validointi on se, mikä estää korruptoituneen tai väärin tunnistetun tiedoston tulkitsemisen hyvin vanhaksi työkirjaksi
Kolme sukupolvea, kolme tietueasettelua
Solutietueet ovat kohta, jossa sukupolvet eroavat toisistaan näkyvimmin. BIFF2 varaa yhtenäisen lohkon matalia tietuenumeroita, $0001:sta $0005:een tyhjille, kokonaisluku-, numero-, otsikko- ja totuusarvo-tai-virhesoluille, ja jokainen runko kantaa kolmitavuisen attribuuttikentän kohdassa, johon myöhemmät versiot laittavat laajennetun muotoindeksin. BIFF3 ja BIFF4 hylkäävät tämän ja käyttävät uudelleen BIFF5:n tietuenumeroita ja asetteluja, $0201, $0203, $0204 ja $0205, kaksitavuisella XF-indeksillä
Tämä viimeinen yksityiskohta aiheuttaa tietyn ja helposti väärin diagnosoitavan virheen. BIFF3- tai BIFF4-LABEL-tietue on rakenteeltaan identtinen BIFF5-vastineensa kanssa, rivi ja sarake, joita seuraa muotoindeksi ja sitten merkkimäärä. Kirjoita lukija, joka olettaa BIFF2-asettelun, ja se lukee kaksi tavua liian vähän, kävelee sitten tietueen lopun yli ja tulkitsee väärin kaiken sen jälkeisen. Oire ei ole poikkeus; se on työkirja, joka luetaan uskottavan roskan kanssa
Kaavatietueet varaavat rinnakkaisen numeroinnin kaikkien kolmen yli, $0006, $0206 ja $0406. Kun kaava tuottaa merkkijonotuloksen, tämä merkkijono saapuu erillisessä seuraavassa tietueessa, $0007 tai $0207, ja sen BIFF2-muoto käyttää yksitavuista pituusetuliitettä myöhemmin käytetyn kaksitavuisen sijaan
Miksi kaavat palautuvat arvoina, ei tekstinä
HotXLS lukee kaavan välimuistiin tallennetun tuloksen näissä tiedostoissa eikä yritä rakentaa kaavalauseketta uudelleen. Tämä on tietoinen raja, ei aukko, joka odottaa täyttämistä
BIFF2:sta BIFF4:ään jäsennetty lauseke käyttää tokenikoodausta, joka eroaa BIFF5:sta ja myöhemmistä tavoilla, jotka menevät kosmetiikkaa syvemmälle: tokenien pituudet on etuliitetty eri tavalla, viittaustokeneilla on eri koot, ja funktioindeksitaulut numeroitiin uudelleen sukupolvien välillä. Näiden tavujen ajaminen BIFF8-lausekekääntäjän läpi ei tuota väärää kaavaa, se tuottaa satunnaisen. Välimuistiin tallennetun arvon lukeminen antaa sen luvun tai merkkijonon, jonka Excel viimeksi laski, mikä on juuri sitä, mitä arkistomigraatio todella tarvitsee
Välimuistiin tallennettu arvo asuu sukupolvesta riippuvassa siirtymässä tietueen sisällä: tavu 7 BIFF2:lle ja tavu 6 BIFF3:lle ja BIFF4:lle. Erikoisarvot, merkkijonot, totuusarvot, virheet ja tyhjät, koodataan merkintäsanaan $FFFF erottelijan kanssa, saman käytännön, jonka myöhemmät BIFF-sukupolvet säilyttivät
Yhden avaaminen
Kutsuva koodi on huomaamaton, ja juuri se on pointti. Tunnistus tapahtuu Open-metodin sisällä:
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[] on 1-pohjainen
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;
Huomaa tuossa silmukassa oleva indeksiaritmetiikka. UsedRange-rajat ovat nollapohjaisia, kun taas sekä taulukkokokoelma että solujen käyttö ovat ykköspohjaisia, epäjohdonmukaisuus, joka on vanhempi kuin nykyinen API ja säilytetään yhteensopivuuden vuoksi. Säädön unohtaminen tarkastaa väärän suorakulmion eikä samalla raportoi mitään epätavallista. Halvat esitarkistukset, jotka välttävät tiedoston lataamisen kokonaan, käsitellään artikkelissa kevyt työkirjan tarkastus
Mitä et saa ja mitä sille voi tehdä
Muotoilua ei tulkita. HotXLS ei jäsennä näiden sukupolvien XF- ja FONT-tietueita, joten fontit, värit, reunukset ja lukumuodot eivät ole käytettävissä, ja solut, jotka Excel kerran näytti päivämäärinä, palautuvat raakoina sarjanumeroinaan
Tämä viimeinen asia täytyy käsitellä omassa koodissasi eikä lukijassa, ja syy on rehellinen: lukumuodot BIFF2:sta BIFF4:ään eivät ole tarpeeksi luotettavia ohjaamaan automaattista päivämääräpäätöstä. Sarake viisinumeroisia lukuja voi olla päivämääriä, tai ne voivat olla osanumeroita. Muunna harkitusti käyttäen työkirjan päivämääräjärjestelmää, jonka säännöt kuvataan artikkelissa päivämäärän sarjanumerot, 1904-järjestelmä ja lukumuodot:
// Päätä sarakekohtaisesti, ei koskaan arvokohtaisesti: viisinumeroinen luku voi olla
// päivämäärä tai osanumero, eikä vanha muoto kerro sitä sinulle
if ColumnHoldsDates(C) then
begin
// Kaksi päivämääräjärjestelmää ovat 1462 päivän päässä toisistaan, joten sama sarjanumero
// tarkoittaa kahta päivämäärää, jotka ovat neljän vuoden päässä toisistaan. Lue järjestelmä
// työkirjasta olettamisen sijaan
if Book.Date1904 then
Writeln(DateToStr(SerialToDate1904(V)))
else
Writeln(DateToStr(SerialToDate1900(V)));
end
else
Writeln(VarToStr(V));
Kaksi rakenteellista huomiota täydentää kuvan. Salasanasuojaus- ja koodisivutietueet esiintyvät yhden laskentataulukon virran sisällä työkirjatason virran sijaan, koska ei ole olemassa työkirjatason virtaa, johon ne voisi laittaa, joten ne täytyy tunnistaa laskentataulukon kontekstissa. Ja BIFF2:sta BIFF4:ään tiedosto sisältää täsmälleen yhden taulukon alivirran; monitaulukkoisia työkirjoja ei ollut olemassa ennen kuin muoto sai säiliönsä
Käytännöllinen migraatiopolku on siis kaksivaiheinen: lue vanha tiedosto sen arvoja varten, kirjoita sitten nykyaikainen työkirja, joka kantaa nuo arvot itse soveltamallasi muotoilulla. Vanhojen tiedostojen lukeminen, nykyaikainen kirjoittaminen ja kaikki niiden välillä toimivat yhdessä kirjastossa Delphille ja C++Builderille, kuvattuna sivulla HotXLS Delphi -laskentataulukkokomponentin sivulla