---
title: "Read an ODS spreadsheet in C#"
url: https://recursiveai.org/onedocument/cookbook/read-ods-spreadsheet/
description: "Read an ODS spreadsheet in C# with OneDocument for .NET 10, with typed inspection, a runnable example and actual output."
version: "1.0.0"
---

# Read an ODS spreadsheet in C#

**OneDocument** is a free, open-source Word, Excel and PowerPoint document library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneDocument.Spreadsheets) · [GitHub](https://github.com/recursive-ai-oss/onedocument-csharp) · [Docs](https://recursiveai.org/onedocument/docs/) · [Download example (.zip)](https://recursiveai.org/onedocument/cookbook/read-ods-spreadsheet/read-ods-spreadsheet.zip)

`.ods` is the spreadsheet format OpenOffice and LibreOffice Calc save. Read its typed cells and stored formula results without opening a desktop spreadsheet app.

```shell
dotnet add package RecursiveAI.OneDocument.Spreadsheets
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneDocument.Spreadsheets;
using var book = Workbook.Open("stock.ods");
Console.WriteLine(book.Sheets[0]["D1"].Text);
```

`stock.ods` is in the example. The snippet prints:

```text
99
```

99 is the value saved in the file; call `Recalculate()` to get 5.

Unzip [the example](https://recursiveai.org/onedocument/cookbook/read-ods-spreadsheet/read-ods-spreadsheet.zip), then `dotnet run`.

## The full program

`stock.ods` is included in the example. Its Stock sheet has A1 = `Pens`, B1 = `2`, C1 = `3`, and D1 = `SUM(B1:C1)` with a deliberately stale cached value of `99`.

The full program reads those four cells, lists import losses, then explicitly recalculates D1.

```csharp
using RecursiveAI.OneDocument.Spreadsheets;

using var book = Workbook.Open("stock.ods");
var sheet = book.Sheets[0];
foreach (string address in new[] { "A1", "B1", "C1", "D1" })
    Console.WriteLine($"{address}: {sheet[address].Value.Kind} {sheet[address].Text}");
var losses = book.ImportLoss?.Items ?? [];
Console.WriteLine($"Import losses: {losses.Count}");
foreach (var loss in losses)
    Console.WriteLine($"{loss.Code}: {loss.Message}");
Console.WriteLine($"Formula: {sheet["D1"].Formula}");
book.Recalculate();
Console.WriteLine($"After recalculation: {sheet["D1"].Text}");
```

```text
A1: Text Pens
B1: Number 2
C1: Number 3
D1: Number 99
Import losses: 0
Formula: SUM(B1:C1)
After recalculation: 5
```


## Variations

Save the imported workbook as XLSX without recalculating. This writes `stock.xlsx` and keeps the stored result:

```csharp
using RecursiveAI.OneDocument.Spreadsheets;
using var book = Workbook.Open("stock.ods");
book.SaveAs("stock.xlsx");
Console.WriteLine(book.Sheets[0]["D1"].Text);
```

```text
99
```

## Related recipes

[Read Excel cells](https://recursiveai.org/onedocument/cookbook/read-excel-file/) · [Recalculate formulas](https://recursiveai.org/onedocument/cookbook/recalculate-excel-formulas/)

## The short answer

To read an OpenOffice spreadsheet in C#, first check the format of the actual file. An ODS file is an OpenDocument spreadsheet, not an XLSX file with a different extension. OneDocument’s `Workbook.Open` detects ODS content and imports it into the same workbook model used for XLSX. Read cells through the worksheet’s address indexer, and inspect `Value.Kind` before treating their contents as numbers or text.

The example deliberately separates reading a formula from calculating it. D1 stores both a formula and the cached result `99`. Opening the file reads that saved result. It does not silently replace it with `5`. This is useful when you need to inspect what the producer actually saved, rather than change the document during import.

## How do I read an OpenOffice Excel file in C#?

Use the snippet at the top for a single cell and the full program for typed values. The [ODS documentation](https://recursiveai.org/onedocument/docs/ods/) says that `Workbook.Open` sniffs the content: the extension does not decide the input format. ODS, spreadsheet templates in OTS, and flat FODS are supported by the OpenDocument spreadsheet layer.

The importer converts the source to an in-memory XLSX package wrapped by `Workbook`. That makes an address such as B1 usable through the ordinary worksheet API, but it is a conversion, not a promise that every ODF feature has an identical workbook counterpart. The sample has only text, numbers and a simple formula, so its import loss count is zero. For an unfamiliar workbook, enumerate `ImportLoss.Items` as the full program does before accepting the result.

Examples of documented import losses include shapes, pictures and charts, rich-text formatting inside cells, filter conditions and features without a workbook counterpart. The text of a rich-text cell is kept even when its internal formatting is reported as a loss. A zero count on this sample says nothing about a different input.

## How do I read typed cell values?

Use `Text` when you want a textual representation of a stored cell value. Use `Value.Kind` and the typed value members when downstream code needs to distinguish strings from numbers. Do not infer the type from whether the displayed text looks numeric: an identifier may legitimately be text.

Formula cells need a second decision. Read the stored result when reproducing the source’s saved state. Call `Recalculate` when you want the calculation engine to compute results now. The full program demonstrates that decision with a visible change from `99` to `5`. A formula that cannot be parsed, uses an unsupported dialect, or refers to another document can instead retain its cached value as a constant with a defect, as the ODS docs explain.

## How do I convert OpenOffice to Excel?

The variation imports the supplied ODS and saves `stock.xlsx`. It does not call `Recalculate`, so the saved cached value remains `99`. Recalculate before saving if fresh results are part of your conversion requirement.

Review the import loss report before treating a conversion as acceptable. Saving the imported model to XLSX cannot reconstruct a feature already dropped during ODS import. For a read-only inspection that needs no conversion output, leave out `SaveAs` entirely and dispose the workbook after reading.
