---
title: "Read and write compound files"
url: https://recursiveai.org/onearchive/cookbook/compound-files/
description: "Write a Microsoft compound file with OneArchive and read it back the same way as a .doc, .xls, .ppt or .msg file: storages are directories and streams are…"
version: "0.7.0-preview.1"
---

# Read and write compound files

Write a Microsoft compound file with OneArchive and read it back the same way as a `.doc`, `.xls`, `.ppt` or `.msg` file: storages are directories and streams are files.

The writer is new in 0.7.0-preview.1:

```csharp
using RecursiveAI.OneArchive;
using System.Text;

// Write a Microsoft compound file: storages are directories, streams are files.
byte[] summary = Encoding.UTF8.GetBytes("Quarterly notes");
byte[] chart = new byte[10_000];
Archive.Create("notes.cfb")
    .Add(new ArchiveEntry { Name = "Summary", Kind = ArchiveEntryKind.File, Size = summary.Length }, summary)
    .Add(new ArchiveEntry { Name = "Attachments", Kind = ArchiveEntryKind.Directory }, [])
    .Add(new ArchiveEntry { Name = "Attachments/chart", Kind = ArchiveEntryKind.File, Size = chart.Length }, chart)
    .Save();

byte[] head = File.ReadAllBytes("notes.cfb")[..8];
Console.WriteLine($"notes.cfb: {new FileInfo("notes.cfb").Length:N0} bytes, signature {Convert.ToHexString(head)}");

// Read it back, the same way as a .doc, .xls, .ppt or .msg file.
using var cfb = Archive.Open("notes.cfb");
foreach (var e in cfb.Entries) Console.WriteLine($"  {e.Kind,-9} {e.Size,6:N0}  {e.Name}");
using var s = cfb.OpenEntry(cfb.Find("Summary")!);
Console.WriteLine($"Summary: {new StreamReader(s).ReadToEnd()}");
```

```text
notes.cfb: 12,800 bytes, signature D0CF11E0A1B11AE1
  File          15  Summary
  Directory      0  Attachments
  File      10,000  Attachments/chart
Summary: Quarterly notes
```

## Good to know

- `Archive.Open` detects a compound file by its signature, `D0 CF 11 E0 A1 B1 1A E1`, so legacy Office files and Outlook messages open without naming the format. `Entries` then lists their storages and streams, such as `WordDocument` or `Workbook`.
- `ArchiveBuilder.Add(entry, bytes)` needs the entry’s `Size` to match the content; a mismatch is an `ArgumentException`.
- The writer writes version 3 (512-byte sectors, the default) or version 4 (4096-byte sectors), set with `CompoundFileWriterOptions`.
- The reader validates strictly and has its own limits, including `MaxDirectoryEntries`.

The format details are in [compound files](https://recursiveai.org/onearchive/docs/cfb/).
