HotXLS leest en schrijft Excel Binary Workbook-bestanden (XLSB) vanuit Delphi via dezelfde TXLSXWorkbook-facade die voor XLSX dient: Open herkent een binair werkboek aan de pakketinhoud, en SaveAs of SaveAsChecked met xlsxExcelBinaryWorkbook schrijft er een. De backend dekt een gevalideerde subset en weigert alles wat hij niet kan representeren voordat hij de bestemming aanraakt
Die laatste clausule is het deel dat u langzaam moet lezen. XLSB oogt als een simpele variatie op XLSX, en in pakketermen is het dat ook. De problemen schuilen in de details die de twee formaten anders coderen, en in wat een bibliotheek stilletjes aanneemt wanneer hij het ene in het andere omzet. De meest leerzame bug in deze backend was helemaal geen misvormd record. Het was een default font dat verdween, en een datumkolom die in Excel veranderde in #### terwijl de waarde, de formatcode en de kolombreedte allemaal klopten
Wat is een XLSB-bestand, en hoe verschilt het van XLSX?
Een XLSB-bestand is een OPC-pakket met exact de part-structuur van een XLSX-werkboek, maar de workbook-, worksheet-, style- en shared-string-parts bewaren binaire records in plaats van XML. Het formaat is gespecificeerd in [MS-XLSB], en de recordcodering heet vaak BIFF12. U krijgt nog steeds [Content_Types].xml, relationship-parts en een ZIP-container; wat verandert is dat xl/workbook.bin xl/workbook.xml vervangt, xl/worksheets/sheet1.bin de worksheet-XML, enzovoort
Elk BIFF12-record begint met een compacte header van variabele lengte. Het recordtype neemt een of twee bytes in, zeven bits per byte met de hoge bit als vervolgvlag, dus een recordtype past in 14 bits. De payloadgrootte volgt in een tot vier bytes met hetzelfde zeven-bits-schema. Strings zijn een 32-bits tekentelling gevolgd door UTF-16-code-eenheden. Vergeleken met BIFF8 is dit een stuk nettere opbouw: geen opsplitsing in 8224-byte CONTINUE, geen compressed-versus-wide-stringvlaggen middenin een record. Vergeleken met XLSX slaat het XML-tokenizeren volledig over, en daarom zijn grote XLSB-bestanden doorgaans kleiner op schijf en sneller voor Excel om te openen
Eén pakketafwijking doet detectiecode struikelen. Excel registreert het XLSB-workbookpart met het content type application/vnd.ms-excel.sheet.binary.macroEnabled.main, zelfs voor werkboeken zonder macros. HotXLS controleert die registratie eerst in [Content_Types].xml en valt alleen terug op de .bin-part-extensie wanneer het content type ontbreekt, en beide routes moeten bovendien door de strenge recordvalidator. De algemene regels over part-namen, relationships en content types zijn dezelfde als behandeld in waarom Excel een geldige XLSX repareert en de OPC-pakketregels erachter
Wanneer kiest u XLSB boven XLSX?
Kies XLSB wanneer een stroomafwaarts systeem het eist of wanneer u grote waardenzware werkboeken uitwisselt met Excel-gebruikers die om de openingstijd geven; anders blijft XLSX de veiligere default. XLSX is een ISO-standaard (ISO/IEC 29500) met brede tool-ondersteuning, hij is te inspecteren met een ZIP-tool en een teksteditor, en elk spreadsheetproduct leest hem. XLSB is een Microsoft-formaat met een gepubliceerde specificatie maar een smaller ecosysteem
In de praktijk komen de verzoeken uit twee hoeken. Sommige rapportagepijplijnen en archieven zijn jaren geleden op .xlsb gestandaardiseerd en weigeren al het andere. Andere teams genereren werkboeken met honderdduizenden numerieke cellen en merkten dat gebruikers de binaire versie merkbaar sneller openen. Beide zijn legitieme redenen. "Klinkt efficiënter" is dat niet, want de binaire backend van HotXLS zet het complete pakket in het geheugen klaar, dus het is niet de tool voor serverexports met begrensd geheugen. Voor die laatste is de streaming XLSX-schrijver het juiste pad
XLSB openen en opslaan met TXLSXWorkbook
TXLSXWorkbook.Open heeft geen formaathint nodig: dezelfde aanroep laadt XLSX, XLSM of XLSB, en na een geslaagde binaire laad meldt TXLSXWorkbook.SourceFormat xlsxExcelBinaryWorkbook. Schrijven is expliciet. SaveAs(FileName) zonder formaat levert altijd een Open XML-werkboek op, ook wanneer de bestandsnaam op .xlsb eindigt, dus benoem bij binaire uitvoer altijd het formaat
uses
SysUtils, lxHandleX;
procedure ConvertToXlsb(const Source, Target: string);
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// Open detecteert XLSX, XLSM of XLSB uit het pakket zelf
if Book.Open(Source) <> 1 then
raise Exception.Create('Input is unsupported or invalid');
// De extensie alleen selecteert nooit binaire uitvoer
if Book.SaveAsChecked(Target, xlsxExcelBinaryWorkbook) <> 1 then
raise Exception.Create('XLSB output is unsupported or failed');
finally
Book.Free;
end;
end;
Streamuitvoer gaat via SaveAs(Stream, xlsxExcelBinaryWorkbook) of de stream-overload van SaveAsChecked. Intern routes beide naar de private methoden SaveAsXlsbStream en SaveAsXlsbFile; die roept u nooit rechtstreeks aan. Bestandsuitvoer wordt klaargezet in een tijdelijk bestand ernaast en gecommit met één definitieve vervanging. Een streambestemming moet leesbaar en seekable zijn, want de schrijver maakt een momentopname van zijn bytes, grootte en positie en herstelt die als de definitieve kopie mislukt. TXLSXWorkbook.LastSaveUsedStreaming meldt False na een binaire opslag, en dat klopt: het hele pakket bestaat in het geheugen voordat ook maar één byte uw bestemming bereikt
Waarom een gevalideerde subset in plaats van volledige getrouwheid?
HotXLS onderhoudt geen tweede objectmodel voor XLSB. Bij het openen converteert XlsbToOpenXml het binaire pakket naar een Open XML-pakket in het geheugen en laadt de gewone XML-parser het; bij het opslaan bouwt de XML-schrijver een pakket en codeert OpenXmlToXlsb het als binaire records. Elke functie moet dus twee vertalingen overleven, en een functie die de brug niet exact kan vertalen wordt geweigerd in plaats van benaderd
De ondersteunde set sinds HotXLS 2.384.113 is ruim genoeg voor de meeste datawerkboeken: getypeerde waarden, shared en inline strings, gangbare fonts, fills, randen en getalnotaties, rijhoogten en kolombreedtes, gewone celformules met gecachte resultaten, gedefinieerde namen, samengevoegde cellen, hyperlinks, bevroren en gesplitste vensters, AutoFilter-bereiken met simpele eigen criteria, en gewone worksheettabellen. Buiten die set vallen shared- en array-formules, future- en user-defined functions, verwijzingen naar externe werkboeken, grafieken en tekeningen, PivotTables en slicers, VBA, voorwaardelijke opmaak, gegevensvalidatie en niet-default berekeningsinstellingen zoals handmatige berekening of iteratie
Weigering is verplicht, geen advies. TXLSXWorkbook.GetConversionReport(xlsConversionExcelBinaryWorkbook) somt niet-ondersteunde functies op voordat u opslaat, en die entries laten de opslag mislukken, ook met AAllowLossy = True of een ongecontroleerde SaveAs. Dat is opzettelijk. Stilletjes een PivotTable uit een binaire kopie laten vallen is het soort verlies dat niemand opmerkt totdat het werkboek voor een klant ligt
uses
Classes, lxHandleX, lxDiagnostics;
function CanSaveAsXlsb(Book: TXLSXWorkbook; Log: TStrings): Boolean;
var
Report: TXLSConversionReport;
I: Integer;
begin
Report := Book.GetConversionReport(xlsConversionExcelBinaryWorkbook);
try
Result := True;
for I := 0 to Report.Count - 1 do
if Report[I].Fidelity = xlsConversionUnsupported then
begin
Result := False;
Log.Add(Report[I].SheetName + ' ' + Report[I].Location + ': ' +
Report[I].Feature + ' - ' + Report[I].Message);
end;
finally
Report.Free; // de aanroeper is eigenaar van het rapport
end;
end;
Het rapport dekt het levende model. De uiteindelijke pakketvalidatie blijft de laatste poort voor zaken die het model nooit ziet, zoals misvormde records of onbekende attributen in het bronbestand, dus een schoon rapport gevolgd door een mislukte opslag is mogelijk, en op het opslagresultaat handelt u
Waarom verdwenen het default font en het 0.00-formaat?
Het default font en de ingebouwde getalnotaties verdwenen omdat de XML-style-lezer twee aannames maakte die opgaan voor bestanden die HotXLS zelf schrijft, maar niet voor werkboeken die Excel schrijft. De brug behield beide resources perfect; het verlies gebeurde één laag hoger, in het publieke Open-pad. Dat gat is de hoofdles van deze backend: een correcte formaatbrug garandeert geen getrouwe publieke round trip
De eerste aanname ging over fonts[0]. Slaat HotXLS XLSX op, dan schrijft hij een impliciet default font in slot nul, en zijn XML-lezer slaat dat slot over zodat de gebruikersgerichte collectie Fonts bij index nul begint. Een door Excel geschreven XLSB voert in dat slot zijn eigen expliciete default mee, en door hem over te slaan werd die keuze weggegooid. De tweede aanname ging over getalnotaties. De lezer mapte alleen custom numFmtId-waarden (164 en hoger) in NumberFormats; ingebouwde id's bleven nul. Een opgemaakte lege cel met ingebouwd formaat 2 — dat is 0.00 — kwam als General terug
De fix zit volledig in het binaire importpad. Nadat het volledige pakket de preflight passeert, zet de XLSB-open een private style-modus alleen voor de synchrone XML-parse. In die modus laadt de lezer elk font inclusief slot nul en verschuift elke fontId met één, converteert elke ondersteunde ingebouwde id naar een expliciete formatcode in het model, en gebruikt voor datumdetectie nog steeds de originele numFmtId, zodat een ingebouwd datumformaat zijn datumbetekenis houdt. Een finally-blok ruimt de modus altijd op, en een latere gewone XLSX- of ODS-Open ruimt ook de vastgehouden default-font-status op
Hoe beïnvloedt fonts[0] de Excel-kolombreedtes?
Excel berekent kolombreedtes vanuit het default font van het werkboek in fonts[0], niet vanuit de fonts die op de cellen in die kolom staan. De kolom-width wordt bewaard in tekenheden van de maximale cijferbreedte van het default font, dus fonts[0] wijzigen verandert de pixelbreedte van elke kolom, ook van kolommen waarvan alle cellen een ander font gebruiken
Dat leverde het meest verwarrende symptoom van het hele onderzoek op. Het opnieuw opgeslagen werkboek had identieke celwaarden, identieke formatcodes en identieke width-attributen, het celfont en de Normal-style wezen allebei naar het behouden font, en Excel rendere een datumkolom desondanks als ####. Het weggeschreven fonts[0] was teruggevallen op Calibri 11, de maximale cijferbreedte kromp, en de data pasten niet meer. HotXLS houdt het default font van de bron nu vast en schrijft het terug als fonts[0], met terugval op Calibri 11 alleen voor werkboeken die nooit een binaire bron hadden. De volledige breedteberekening staat in Excel-kolombreedte en max digit width (MDW) in Delphi
Locale-afhankelijke ingebouwde formaten worden geweigerd, niet gegokt
Een ingebouwd getalnotatie-id zonder expliciete formatcode wordt alleen geaccepteerd wanneer zijn betekenis vastligt; locale-afhankelijke id's worden geweigerd tijdens de pakketpreflight. HotXLS mapt id's 0 tot 22, 37 tot 40 en 45 tot 49 op bekende codes zoals 0.00, 0%, mm:ss en @. De overige id's onder 164 horen bij formaten waarvan de weergave afhangt van de regionale instellingen van de Excel-installatie, en de import weigert ze met de melding "A locale-dependent number format requires an explicit format code"
Een code verzinnen voor die id's zou erger zijn dan falen. Een gegokt Oost-Aziatisch datapatroon oogt plausibel, doorloopt de round trip zonder fout en toont de verkeerde dingen aan de helft van uw gebruikers. Ook timing telt: de controle draait in de hele-pakket-preflight, voordat het bestaande werkboek wordt gewist, dus een geweigerd bestand laat het eerder geladen model, de bestandsnaam en het bronformaat onaangeroerd. Het artikel over Excel date serial en numFmt behandelt hoe ingebouwde datum-id's samenhangen met de 1900- en 1904-datumstelsels
procedure LoadBinaryWorkbook(Book: TXLSXWorkbook; const FileName: string);
var
I: Integer;
begin
// Binaire invoer vraagt om volledig eager laden; selectieve modi weigeren vooraf
Book.MetadataOnly := False;
Book.SelectedSheets.Clear;
if Book.Open(FileName) <> 1 then
begin
for I := 0 to Book.Diagnostics.Count - 1 do
Writeln(Book.Diagnostics[I].Message);
Exit; // het eerder geladen werkboek is nog intact
end;
// Formule-uitvoer heeft een cache nodig tenzij de opslag herberekent
Book.RecalcBeforeSave := xrmAlways;
end;
Praktische regels voor XLSB in productiecode
Op de binaire backend is te vertrouwen wanneer u zijn weigeringen behandelt als data in plaats van als te onderdrukken fouten. Een paar regels volgen uit het gedrag hierboven
- Benoem het formaat bij elke binaire opslag; de
.xlsb-extensie alleen levert nog steeds XLSX op - Draai
GetConversionReport(xlsConversionExcelBinaryWorkbook)vóór het opslaan van door gebruikers bewerkte werkboeken en toon de niet-ondersteunde functies aan de gebruiker - Houd
MetadataOnlyuit enSelectedSheetsleeg bij binaire invoer, want lazy loading zou vragen om een geconverteerd archief vast te houden - Geef formules een gecacht resultaat of reken herbereken vóór het opslaan, want een ontbrekende cache weigert onder
xrmManualen onder een schonexrmIfDirty - Begroot geheugen voor het complete geconverteerde pakket plus de binaire uitvoer; gebruik streaming XLSX wanneer het geheugen begrensd moet blijven
Vergelijk bij het testen met Excel via de publieke API in plaats van op brugniveau. De default-font- en 0.00-regressies slaagden allebei voor bruggests, en beide verschenen direct in een door Excel geschreven werkboek dat via Open en SaveAsChecked werd geopend en opnieuw opgeslagen
FAQ
Detecteert HotXLS XLSB-bestanden automatisch?
Ja. TXLSXWorkbook.Open inspecteert het content type dat voor het workbookpart is geregistreerd en valideert de binaire records, dus dezelfde aanroep laadt XLSX en XLSB, en SourceFormat meldt welke is gelezen
Waarom schrijft SaveAs met een .xlsb-bestandsnaam nog steeds XLSX?
HotXLS leidt het uitvoerformaat nooit af uit de extensie. Geef xlsxExcelBinaryWorkbook door aan SaveAs of SaveAsChecked om een binair werkboek te schrijven
Wat gebeurt er wanneer een werkboek functies buiten de XLSB-subset gebruikt?
De opslag mislukt voordat de bestemming verandert, ook met lossy opslag toegestaan. GetConversionReport somt de blokkerende functies vooraf op, en Diagnostics legt de mislukking achteraf uit
XLSB-ondersteuning, het conversierapport en de rest van de werkboek-API zitten in HotXLS, de native Delphi- en C++Builder-spreadsheetcomponent