Choosing a text format
The three line formats cover different jobs. This guide helps you pick, and explains what round-trips faithfully and how each parser recovers from dirty input.
Decision matrix
| You have / need | Reach for |
|---|---|
| Tabular data exchanged with spreadsheets, databases, other systems | Delimited (Bodu.Text.Delimited) |
| Per-environment process settings, secrets injected at deploy time | DotEnv (Bodu.Text.DotEnv) |
| Human-owned configuration with sections and comments | INI (Bodu.Text.Ini) |
| Layered configuration with glob targets and typed views (EditorConfig-style) | Bodu.Text.Configuration |
| Nested structures, arrays, non-string scalars | TOML / YAML / Bencode (the structured-text quartet) |
The line formats are flat: Delimited is an array of records, DotEnv a single object, INI a two-level object-of-objects. If your data nests deeper, use a structured format instead of encoding structure into key names.
Round-trip fidelity
- Delimited round-trips values exactly; layout is canonicalized (quotes are emitted only where required, rows end in the writer's line ending). Use the mutable
DelimitedNodeDOM to parse → edit → rewrite. - DotEnv round-trips keys, values, and each entry's
exportflag through the mutable DOM; quoting is canonicalized on write. - INI is the fidelity flagship: the mutable
IniNodeDOM preserves every leading comment line and the end-of-scope comment block, so parse → edit → write keeps a human's annotations. Whitespace around=is canonicalized (key=value), and global entries are always emitted before the first section header. Inline comments are not modeled - the dialect treats them as value content.
The read-only *Document DOMs are for querying, not round-tripping: they drop comment trivia.
Mutation
Author or edit through the mutable node DOMs - insertion-ordered maps (DotEnvObject, IniObject) or record lists (DelimitedArray), written back with ToUtf8Bytes() / ToString() or WriteTo(ref Utf8*Writer) for custom writer options (e.g. a tab delimiter). For typed data, skip the DOM entirely and round-trip POCOs through the *Serializer.
Parser error recovery
All three readers throw their *FormatException with a line/offset by default. Leniency is opt-in per dialect:
- Delimited -
FieldCountBehavior.Raggedaccepts records whose field count differs from the header;MalformedRecordBehavior.SkipRecordtruncates a structurally broken record instead of throwing;DuplicateHeaderBehaviorpicks a winner for repeated column names. - DotEnv - the reader is line-incremental, so one malformed line fails fast with its position; quoting errors (an unterminated quote) always throw.
- INI - malformed lines (no
=, unterminated[section) always throw; duplicate sections and keys are resolved by the document-model policies (Merge/Disallowed,LastWins/FirstWins/Disallowed).
See Parser policies for the full table.