XLS File Documentation


Summary

An .xls file is the legacy binary workbook of Microsoft Excel, used by default from Excel 97 through Excel 2003. It stores worksheets, formulas, and formatting as BIFF8 records inside an OLE2 container, and its MIME type is application/vnd.ms-excel. Excel 2007 replaced it with the XLSX format.

You can open .xls for free in LibreOffice Calc, Google Sheets, or Apple Numbers without a Microsoft license.

Technical details

FeatureValue
Full nameMicrosoft Excel 97-2003 Workbook (BIFF8)
File extension.xls
MIME typeapplication/vnd.ms-excel
Format typeOLE2 / Compound File Binary container holding BIFF8 records
DeveloperMicrosoft
Introduced1987; BIFF8 covers Excel 97-2003; superseded by XLSX in 2007
Container / base formatOLE2 / Compound File Binary (CFB)
Magic numberD0 CF 11 E0 A1 B1 1A E1
Byte orderLittle-endian
Main internal stream"Workbook" (older files: "Book")
Record structure2-byte opcode + 2-byte length + payload
Max rows per sheet65,536 (216)
Max columns per sheet256 (28)
Number precisionIEEE-754 64-bit double
Macro supportYes (VBA project stream inside the container)
CompressionNone on the container; strings deduplicated via SST
Open standardNo (published spec, proprietary format)
Related extensions.xlsx .xlsm .xlsb .xlt .csv .ods
Specification[MS-XLS] Excel Binary File Format
File signature (magic bytes)
D0 CF 11 E0 A1 B1 1A E1

These 8 bytes are the OLE2 / Compound File Binary (CFB) header at offset 0. Every legacy binary Office document shares them, so a .doc, .ppt, and .xls all begin identically, as do other CFB containers such as MSI installers and Thumbs.db. The signature alone does not identify a workbook. An XLS is recognized by reading the CFB directory and finding a stream named "Workbook" (older files use "Book"), which holds the BIFF8 records. Contrast this with the modern XLSX format, which is a ZIP archive and starts with 50 4B 03 04 ("PK"). If the first bytes are "PK" you have an OOXML file, not a binary XLS.

What is an XLS file?

An XLS file is the binary workbook format that Microsoft Excel used by default from Excel 97 through Excel 2003. Microsoft calls the internal encoding BIFF8, short for Binary Interchange File Format version 8. For roughly a decade it was the standard way spreadsheets were saved and exchanged, which is why the format is still common in archives, email attachments, and systems that export legacy reports.

A single XLS file holds everything about a workbook: the grid of cells across one or more worksheets, cell values and formulas, number and font formatting, defined names, charts, and optionally a VBA macro project. All of it is packed into one binary file rather than a folder of parts. Excel 2007 introduced XLSX as the new default and moved to an XML-based, ZIP-packaged format, but Excel still reads and writes XLS in a compatibility mode.

The OLE2 Compound File container

An XLS is not a flat stream of spreadsheet data. It is an OLE2 file, also called a Compound File Binary (CFB) file. A CFB acts like a small filesystem stored inside a single file: it has a directory, named streams that behave like files, and storages that behave like folders. This is the same container that legacy .doc (Word) and .ppt (PowerPoint) files use, which is why all three begin with the identical 8-byte header.

The file starts with the CFB signature D0 CF 11 E0 A1 B1 1A E1 at offset 0. All multi-byte integers in the header and in the BIFF payload are little-endian. The container divides its content into fixed-size sectors and keeps an allocation table to chain them together, so a logical stream can be scattered across the file and reassembled on read. A typical XLS directory looks like this:

Root Entry  (storage)
 ├─ Workbook               (main BIFF8 stream; older files: "Book")
 ├─ \x05SummaryInformation  (author, title, dates)
 ├─ \x05DocumentSummaryInformation
 └─ _VBA_PROJECT_CUR        (storage, present only if macros exist)
     ├─ PROJECT
     ├─ VBA (storage)
     │   ├─ _VBA_PROJECT
     │   ├─ dir
     │   └─ Module1
     └─ ...

To read a workbook, an application opens the CFB, finds the entry named "Workbook", and parses the BIFF8 records inside it. The property-set streams whose names begin with byte 0x05 hold document metadata such as author and last-saved time.

BIFF8 records: opcode, length, payload

Inside the Workbook stream, data is a sequence of records. Every record has the same simple shape: a 2-byte record type (the opcode), a 2-byte length giving the size of the payload in bytes, then the payload itself.

Offset  Size  Field
  0      2    Record type (opcode, little-endian)
  2      2    Record length (payload bytes)
  4      N    Payload (N = length)

Because the length field is 16 bits, a single record payload cannot exceed 8,224 bytes in BIFF8. When a structure is larger, for example a long shared-string table, it is split across the primary record followed by one or more CONTINUE records (opcode 0x003C). A parser reads the type and length, consumes exactly that many payload bytes, then moves to the next record, stitching CONTINUE payloads onto the record they extend.

Two records frame every logical section. A BOF record (Beginning of File, opcode 0x0809) opens a substream and declares what kind it is, and an EOF record (opcode 0x000A) closes it. The workbook is therefore a series of substreams delimited by BOF/EOF pairs.

Streams and substreams: workbook globals, BOUNDSHEET and worksheets

The first substream is the workbook globals. It holds settings that apply to the whole file: the shared string table, the collection of cell formats, defined names, and one BOUNDSHEET record (opcode 0x0085) for each worksheet in the book. A BOUNDSHEET record stores the sheet name, its visibility state, and a byte offset that points to where that sheet's own substream begins inside the Workbook stream.

That offset is how Excel locates a sheet inside the container without scanning the whole file. After the globals substream, each worksheet appears as its own BOF/EOF-delimited substream containing the sheet's cell records, a DIMENSIONS record giving the used range, and row and column formatting. The order on disk is fixed; the BOUNDSHEET offsets are the index that ties a sheet name to its data.

The Shared String Table

Text values are not stored in the cells that display them. Instead, every distinct string in the workbook is written once into a Shared String Table, the SST record (opcode 0x00FC) that lives in the workbook globals substream. A cell that shows text stores only an integer index into that table.

The benefit is size. A column that repeats the word "Active" ten thousand times stores the string once and then ten thousand small indexes. Because the SST is often larger than the 8,224-byte record limit, it is routinely continued across CONTINUE records, and a well-behaved parser must reassemble the string list before resolving any cell that references it.

Cell records: LABELSST, NUMBER, RK and FORMULA

Within a worksheet substream, individual cells are stored as typed records. Each carries its row and column position (0-based internally) and a reference to a cell format, plus a value whose encoding depends on the record type.

  • LABELSST (opcode 0x00FD) is a text cell. It does not contain the text; it holds a 4-byte index into the Shared String Table.
  • NUMBER (opcode 0x0203) holds a full IEEE-754 64-bit floating-point value.
  • RK (opcode 0x027E) is a compact number. Excel packs integers and simple decimals that fit into 30 bits into this smaller record to save space, avoiding a full 8-byte double.
  • FORMULA (opcode 0x0006) stores a formula as a parsed token sequence plus its most recently calculated result, so a reader can show the value without recomputing.
  • BLANK records carry formatting for an empty cell, and DIMENSIONS records the sheet's occupied bounds.

Dates and times are numbers under this scheme. A date is a serial day count formatted for display, which is why a cell can silently switch between a date and a plain integer depending only on its number format.

The 65,536-row limit and why XLSX replaced it

BIFF8 addresses rows with 16 bits and columns with 8 bits, so a worksheet is capped at 65,536 rows (216) and 256 columns (28). These ceilings are baked into the record layout, not a preference, and they became a real constraint as datasets grew past 65,536 rows.

Excel 2007 introduced XLSX, the Office Open XML successor, which is a ZIP archive of XML parts and raises the grid to 1,048,576 rows and 16,384 columns. XLSX is standardized as ISO/IEC 29500 and begins with the ZIP signature 50 4B 03 04. Microsoft also offers XLSB, a binary form of Office Open XML that keeps records but wraps them in a ZIP; it opens faster than XLSX on very large books while staying inside the modern format family. When newer Excel opens an XLS it runs in Compatibility Mode and warns about features that would be lost if the file is saved back as legacy binary.

VBA macros and the .xls attack surface

The same container flexibility that makes XLS convenient also makes it a classic malware vector. An XLS can hold a VBA project as an extra storage in the CFB, containing compiled, compressed p-code alongside the macro source. A plain XLSX cannot carry macros at all; that requires the separate .xlsm variant. So an .xls received by email should be treated as potentially executable, not as inert data.

The dangerous path is automatic execution. If a workbook defines a procedure named Auto_Open or a Workbook_Open event handler, Excel runs it the moment the file opens, but only after the user clicks "Enable Content" or "Enable Macros" on the security banner. Attackers craft documents that pressure the reader into enabling macros, at which point the VBA runs with the user's privileges. XLS files can also embed OLE objects and external links that pull in further content.

Modern Excel defends this with Protected View, which opens files that came from the internet or an email attachment in a sandboxed, read-only mode where macros do not run until the user explicitly leaves Protected View. Group policy can block macros in files from the internet outright. If you only need to see the data and want no risk from the VBA engine, open the file in Google Sheets or LibreOffice Calc: both read the cell contents without running Microsoft's VBA runtime, so the macro code never executes.

FAQ

Why is XLS a single binary file and not a folder like XLSX? XLS predates the ZIP-of-XML approach. It uses an OLE2 Compound File, which already provides a directory of streams inside one file, so Microsoft had no reason to expose separate parts. XLSX switched to a ZIP of XML documents to make the format open and toolable.

What is the Shared String Table in an XLS? It is a single list of every distinct text value in the workbook. Text cells store an index into this list rather than the text itself, which shrinks files that repeat the same strings across many cells.

How does Excel find a sheet inside the CFB container? The workbook globals substream contains one BOUNDSHEET record per sheet, and each record holds a byte offset pointing to that sheet's substream in the Workbook stream. Excel jumps straight to the offset instead of scanning.

Why can an XLS carry a virus when a plain XLSX cannot? An XLS can store a VBA macro project inside its container, and Excel can be prompted to run that code on open. A plain XLSX holds no macros by design; macro-bearing spreadsheets must use the distinct .xlsm extension, which makes the risk visible from the filename.

References