HotXLS liest und schreibt Excel Binary Workbook-Dateien (XLSB) aus Delphi über dieselbe TXLSXWorkbook-Fassade wie für XLSX: Open erkennt eine Binärmappe am Paketinhalt, und SaveAs oder SaveAsChecked mit xlsxExcelBinaryWorkbook schreibt eine. Das Backend deckt einen validierten Subset ab und lehnt alles, was es nicht repräsentieren kann, ab, bevor es das Ziel anfasst
Diese letzte Klausel ist der Teil, den man langsam lesen sollte. XLSB sieht aus wie eine simple Variation von XLSX, und in Packaging-Begriffen ist es das auch. Der Ärger wohnt in den Details, die die beiden Formate unterschiedlich kodieren, und in dem, was eine Bibliothek stillschweigend annimmt, wenn sie das eine ins andere brückt. Der aufschlussreichste Bug in diesem Backend war gar kein malformed Record. Es war ein verschwundener Default-Font und eine Datumsspalte, die in Excel zu #### wurde, obwohl Wert, Formatcode und Spaltenbreite alle korrekt waren
Was ist eine XLSB-Datei, und wie unterscheidet sie sich von XLSX?
Eine XLSB-Datei ist ein OPC-Paket mit exakt der Part-Struktur einer XLSX-Mappe, aber die Workbook-, Worksheet-, Style- und Shared-String-Parts speichern binäre Records statt XML. Das Format ist in [MS-XLSB] spezifiziert, die Record-Kodierung heißt oft BIFF12. Sie bekommen weiterhin [Content_Types].xml, Relationship-Parts und einen ZIP-Container; geändert wird, dass xl/workbook.bin xl/workbook.xml ersetzt, xl/worksheets/sheet1.bin das Worksheet-XML, und so weiter
Jeder BIFF12-Record beginnt mit einem kompakten Header variabler Länge. Der Record-Typ nimmt ein oder zwei Bytes, sieben Bits pro Byte mit dem High-Bit als Fortsetzungsflag, ein Record-Typ passt also in 14 Bits. Die Payload-Größe folgt in ein bis vier Bytes nach demselben Sieben-Bit-Schema. Strings sind eine 32-Bit-Zeichenanzahl gefolgt von UTF-16-Code-Units. Gegenüber BIFF8 ist das ein deutlich saubereres Layout: kein 8224-Byte-CONTINUE-Splitting, keine Compressed-versus-Wide-String-Flags mitten im Record. Gegenüber XLSX überspringt es das XML-Tokenizing komplett, weshalb große XLSB-Dateien auf der Platte tendenziell kleiner sind und sich für Excel schneller öffnen
Ein Packaging-Detail bringt Erkennungscode zu Fall. Excel registriert den XLSB-Workbook-Part mit dem Content-Type application/vnd.ms-excel.sheet.binary.macroEnabled.main, sogar für Mappen ohne Makros. HotXLS prüft diese Registrierung zuerst in [Content_Types].xml und fällt nur auf die .bin-Part-Extension zurück, wenn der Content-Type fehlt; und beide Wege müssen weiterhin den strikten Record-Validator passieren. Die allgemeinen Regeln zu Part-Namen, Relationships und Content-Types sind dieselben wie in warum Excel ein gültiges XLSX repariert und die OPC-Paketregeln dahinter
Wann sollten Sie XLSB statt XLSX wählen?
Wählen Sie XLSB, wenn ein nachgelagertes System es verlangt oder wenn Sie große, werte-lastige Mappen mit Excel-Nutzern austauschen, denen Öffnungszeit wichtig ist; sonst bleibt XLSX der sicherere Default. XLSX ist ein ISO-Standard (ISO/IEC 29500) mit breiter Tool-Unterstützung, mit einem ZIP-Tool und einem Texteditor inspizierbar, und jedes Tabellenkalkulationsprodukt liest es. XLSB ist ein Microsoft-Format mit publizierter Spezifikation, aber schmalerem Ökosystem
In der Praxis kommen die Anfragen aus zwei Richtungen. Manche Reporting-Pipelines und Archive haben sich vor Jahren auf .xlsb standardisiert und lehnen alles andere ab. Andere Teams generieren Mappen mit hunderttausenden numerischen Zellen und stellten fest, dass Nutzer die Binärversion spürbar schneller öffnen. Beides sind legitime Gründe. „Klingt effizienter“ ist keiner, denn das HotXLS-Binärsystem stagt das komplette Paket im Speicher, es ist also nicht das Werkzeug für Server-Exporte mit begrenztem Speicher. Für die ist der Streaming-XLSX-Writer der richtige Weg
XLSB mit TXLSXWorkbook öffnen und speichern
TXLSXWorkbook.Open braucht keinen Format-Hinweis: Derselbe Aufruf lädt XLSX, XLSM oder XLSB, und nach erfolgreichem Binärladen meldet TXLSXWorkbook.SourceFormat xlsxExcelBinaryWorkbook. Schreiben ist explizit. SaveAs(FileName) ohne Format erzeugt immer eine Open-XML-Mappe, selbst wenn der Dateiname auf .xlsb endet; benennen Sie die Binärausgabe also immer mit dem Format
uses
SysUtils, lxHandleX;
procedure ConvertToXlsb(const Source, Target: string);
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// Open erkennt XLSX, XLSM oder XLSB am Paket selbst
if Book.Open(Source) <> 1 then
raise Exception.Create('Input is unsupported or invalid');
// Die Extension allein wählt nie Binärausgabe
if Book.SaveAsChecked(Target, xlsxExcelBinaryWorkbook) <> 1 then
raise Exception.Create('XLSB output is unsupported or failed');
finally
Book.Free;
end;
end;
Stream-Ausgabe läuft über SaveAs(Stream, xlsxExcelBinaryWorkbook) oder den Stream-Overload von SaveAsChecked. Intern routen beide zu den privaten Methoden SaveAsXlsbStream und SaveAsXlsbFile; direkt aufrufen tun Sie die nie. Dateiausgabe wird in eine Geschwister-Temporärdatei gestagt und mit einem finalen Ersatz committed. Ein Stream-Ziel muss lesbar und seekbar sein, denn der Writer snapshotet seine Bytes, Größe und Position und stellt sie wieder her, falls die finale Kopie failt. TXLSXWorkbook.LastSaveUsedStreaming meldet nach einem Binärspeichern False, was akkurat ist: Das ganze Paket existiert im Speicher, bevor ein einziges Byte Ihr Ziel erreicht
Warum ein validierter Subset statt voller Treue?
HotXLS hält kein zweites Objektmodell für XLSB. Beim Öffnen konvertiert XlsbToOpenXml das Binärpaket in ein Open-XML-Paket im Speicher, und der gewöhnliche XML-Parser lädt es; beim Speichern baut der XML-Writer ein Paket, und OpenXmlToXlsb kodiert es als binäre Records. Jedes Feature muss also zwei Übersetzungen überleben, und ein Feature, das die Brücke nicht exakt übersetzen kann, wird abgelehnt statt angenähert
Der unterstützte Stand seit HotXLS 2.384.113 reicht für die meisten Datenmappen: typisierte Werte, Shared- und Inline-Strings, gängige Fonts, Fills, Borders und Zahlenformate, Zeilenhöhen und Spaltenbreiten, gewöhnliche Zellformeln mit gecachten Ergebnissen, Defined Names, verbundene Zellen, Hyperlinks, eingefrorene und geteilte Panes, AutoFilter-Bereiche mit einfachen eigenen Kriterien und gewöhnliche Worksheet-Tables. Außerhalb liegen Shared- und Array-Formeln, Future- und User-Defined-Functions, Referenzen auf externe Mappen, Charts und Drawings, PivotTables und Slicer, VBA, Conditional Formatting, Data Validation und nicht-Default-Berechnungseinstellungen wie manuelle Berechnung oder Iteration
Ablehnung ist verpflichtend, nicht beratend. TXLSXWorkbook.GetConversionReport(xlsConversionExcelBinaryWorkbook) listet nicht unterstützte Features, bevor Sie speichern, und diese Einträge lassen das Speichern failen, selbst mit AAllowLossy = True oder einem ungeprüften SaveAs. Das ist Absicht. Eine PivotTable stillschweigend aus einer Binärkopie zu werfen ist die Art Verlust, die niemand bemerkt, bis die Mappe vor einem Kunden liegt
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; // der Aufrufer besitzt den Report
end;
end;
Der Report deckt das Live-Modell ab. Die finale Paketvalidierung bleibt die letzte Schranke für Dinge, die das Modell nie sieht, etwa malformed Records oder unbekannte Attribute in der Quelldatei; ein sauberer Report, gefolgt von einem fehlgeschlagenen Speichern, ist also möglich, und auf das Speicherergebnis kommt es an
Warum verschwanden der Default-Font und das 0.00-Format?
Der Default-Font und die Built-in-Zahlenformate verschwanden, weil der XML-Style-Reader zwei Annahmen traf, die für Dateien gelten, die HotXLS selbst schreibt, aber nicht für Mappen, die Excel schreibt. Die Brücke hat beide Ressourcen perfekt erhalten; der Verlust passierte eine Ebene höher, im öffentlichen Open-Pfad. Diese Lücke ist die Hauptlektion dieses Backends: eine korrekte Formatbrücke garantiert keinen treuen öffentlichen Roundtrip
Die erste Annahme betraf fonts[0]. Speichert HotXLS XLSX, schreibt es einen impliziten Default-Font in Slot null, und sein XML-Reader überspringt diesen Slot, damit die nutzerseitige Fonts-Collection bei Index null beginnt. Ein von Excel erzeugtes XLSB trägt seinen eigenen expliziten Default in diesem Slot, und das Überspringen warf diese Wahl weg. Die zweite Annahme betraf Zahlenformate. Der Reader mappte nur Custom-numFmtId-Werte (164 und darüber) in NumberFormats; Built-in-IDs blieben null. Eine formatierte leere Zelle mit Built-in-Format 2, also 0.00, kam als General zurück
Der Fix wohnt vollständig im binären Import-Pfad. Nachdem das komplette Paket das Preflight passiert hat, setzt der XLSB-Open für die synchrone XML-Analyse einen privaten Style-Mode. In diesem Modus lädt der Reader jeden Font inklusive Slot null und verschiebt jede fontId um eins, konvertiert jede unterstützte Built-in-ID in einen expliziten Formatcode im Modell und nutzt weiterhin die ursprüngliche numFmtId für die Datumserkennung, sodass ein Built-in-Datumformat seine Datumssemantik behält. Ein finally-Block räumt den Mode immer weg, und ein späteres schlichtes XLSX- oder ODS-Open löscht auch den gehaltenen Default-Font-Zustand
Wie wirkt sich fonts[0] auf Excel-Spaltenbreiten aus?
Excel berechnet Spaltenbreiten aus dem Workbook-Default-Font in fonts[0], nicht aus den Fonts, die auf die Zellen dieser Spalte angewendet sind. Die Spalten-width wird in Zeicheneinheiten der maximalen Ziffernbreite des Default-Fonts gespeichert; fonts[0] zu ändern ändert also die Pixelbreite jeder Spalte, auch solcher, deren Zellen alle einen anderen Font nutzen
Das produzierte das verwirrendste Symptom der ganzen Untersuchung. Die neu gespeicherte Mappe hatte identische Zellwerte, identische Formatcodes und identische width-Attribute, Zell-Font und Normal-Style zeigten beide auf den erhaltenen Font, und Excel renderte trotzdem eine Datumsspalte als ####. Das geschriebene fonts[0] war auf Calibri 11 zurückgefallen, die maximale Ziffernbreite schrumpfte, und die Daten passten nicht mehr. HotXLS behält jetzt den Quell-Default-Font und schreibt ihn als fonts[0] zurück, mit Rückfall auf Calibri 11 nur für Mappen, die nie eine binäre Quelle hatten. Die volle Breiten-Arithmetik steht in Excel-Spaltenbreite und max digit width (MDW) in Delphi
Locale-abhängige Built-in-Formate werden abgelehnt, nicht geraten
Eine Built-in-Zahlenformat-ID ohne expliziten Formatcode wird nur akzeptiert, wenn ihre Bedeutung feststeht; locale-abhängige IDs werden beim Paket-Preflight abgelehnt. HotXLS mappt die IDs 0 bis 22, 37 bis 40 und 45 bis 49 auf bekannte Codes wie 0.00, 0%, mm:ss und @. Die übrigen IDs unter 164 gehören zu Formaten, deren Darstellung von den regionalen Einstellungen der Excel-Installation abhängt, und der Import verweigert sie mit der Meldung „A locale-dependent number format requires an explicit format code“
Für diese IDs einen Code zu erfinden wäre schlimmer als zu failen. Ein geratenes ostasiatisches Datumsmuster sieht plausibel aus, round-tript fehlerfrei und zeigt der Hälfte Ihrer Nutzer das Falsche an. Auch das Timing zählt: Die Prüfung läuft im Preflight des Gesamtpakets, bevor die bestehende Mappe geleert wird; eine abgelehnte Datei lässt also das zuvor geladene Modell, den Dateinamen und das Quellformat unangetastet. Wie Built-in-Datum-IDs mit den 1900er- und 1904er-Datumsystemen interagieren, behandelt der Excel-Date-Serial-und-NumFmt-Artikel
procedure LoadBinaryWorkbook(Book: TXLSXWorkbook; const FileName: string);
var
I: Integer;
begin
// Binäreingabe braucht eagerly volles Laden; selektive Modi lehnen vorab ab
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; // die zuvor geladene Mappe bleibt intakt
end;
// Formelausgabe braucht einen Cache, außer das Speichern rechnet neu
Book.RecalcBeforeSave := xrmAlways;
end;
Praktische Regeln für XLSB im Produktionscode
Auf das Binärbackend ist Verlass, wenn Sie seine Ablehnungen als Daten behandeln statt als zu unterdrückende Fehler. Ein paar Regeln folgen aus dem Verhalten oben
- Benennen Sie das Format bei jedem Binärspeichern; die
.xlsb-Extension allein erzeugt weiterhin XLSX - Fahren Sie
GetConversionReport(xlsConversionExcelBinaryWorkbook), bevor Sie nutzerbearbeitete Mappen speichern, und zeigen Sie dem Nutzer die nicht unterstützten Features - Lassen Sie
MetadataOnlyaus undSelectedSheetsleer bei Binäreingabe, denn Lazy Loading würde das Zurückbehalten eines konvertierten Archivs erfordern - Geben Sie Formeln ein gecachtes Ergebnis oder rechnen Sie vor dem Speichern neu, denn ein fehlender Cache wird unter
xrmManualund unter einem sauberenxrmIfDirtyabgelehnt - Planen Sie Speicher für das komplette konvertierte Paket plus die Binärausgabe ein; nutzen Sie Streaming-XLSX, wenn der Speicher begrenzt bleiben muss
Testen Sie gegen Excel über die öffentliche API statt auf Brückenebene. Die Default-Font- und 0.00-Regressionen bestanden beide Brückentests, und beide zeigten sich sofort in einer von Excel erzeugten Mappe, geöffnet und neu gespeichert über Open und SaveAsChecked
FAQ
Erkennt HotXLS XLSB-Dateien automatisch?
Ja. TXLSXWorkbook.Open inspiziert den für den Workbook-Part registrierten Content-Type und validiert die binären Records; derselbe Aufruf lädt also XLSX und XLSB, und SourceFormat meldet, was gelesen wurde
Warum schreibt SaveAs mit einem .xlsb-Dateinamen weiterhin XLSX?
HotXLS leitet das Ausgabeformat nie aus der Extension ab. Übergeben Sie xlsxExcelBinaryWorkbook an SaveAs oder SaveAsChecked, um eine Binärmappe zu schreiben
Was passiert, wenn eine Mappe Features außerhalb des XLSB-Subsets nutzt?
Das Speichern failt, bevor sich das Ziel ändert, selbst mit erlaubtem verlustbehaftetem Speichern. GetConversionReport listet die blockierenden Features vorab, und Diagnostics erklärt das Versagen danach
XLSB-Unterstützung, der Conversion-Report und der Rest der Workbook-API kommen in HotXLS, the native Delphi and C++Builder spreadsheet component