IRONSOFTWAREHOME
USING IRONXL

How to Read Open Office Excel Files in C# Without Excel Installed

Curtis Chau
Curtis Chau
Updated: June 28, 2026

Reading and processing OpenDocument Spreadsheet (ODS) and Excel files in C# is straightforward when you use the right library. With IronXL, you load any XLS, XLSX, ODS, or CSV file into a WorkBook object using a single method call -- no Microsoft Excel installation required, no COM registration, and no Interop headaches. This guide walks you through every step: installing the package, loading files, extracting typed cell values, working with named worksheets, handling merged cells, and deploying to Linux or containerized environments.

How Do You Install IronXL in a .NET Project?

NuGet Package Manager Installation

Add IronXL to your project through the NuGet Package Manager. Open the Package Manager Console in Visual Studio and run:

PM > Install-Package IronXL.Excel

IronXL targets .NET 8, .NET 9, .NET 10, .NET Framework 4.6.2+, and .NET Standard 2.0, so it fits modern and legacy codebases alike. Once the package installs, add the using IronXL; directive at the top of any file that works with spreadsheets, and you are ready to load your first workbook.

For Azure Functions, Docker containers, or Linux-hosted APIs, no additional runtime configuration is required. The library bundles everything it needs internally and does not call out to Excel automation components.

How Do You Load an OpenOffice or Excel File in C#?

IronXL treats ODS, XLS, XLSX, and CSV files identically through the WorkBook.Load method. You pass an absolute or relative file path, and the library detects the format from the file header -- not just the extension. This means a file renamed from .ods to .xlsx is still read correctly.

using IronXL;

// Load an OpenDocument Spreadsheet (.ods) produced by LibreOffice Calc or OpenOffice
WorkBook workbook = WorkBook.Load("quarterly_report.ods");

// Access the first worksheet by index
WorkSheet sheet = workbook.WorkSheets[0];

// Read a cell value
string companyName = sheet["A1"].StringValue;
int recordCount   = sheet["B1"].IntValue;

Console.WriteLine($"Company : {companyName}");
Console.WriteLine($"Records : {recordCount}");

The same call works for XLSX and XLS files -- just change the path. WorkBook.Load returns the same strongly-typed object regardless of source format, so the rest of your code stays identical whether the file originates from Microsoft Excel, LibreOffice, or any other ODF-compliant application.

How Do You Read Every Row and Cell in a Worksheet?

Iterating the Rows Collection

Iterating over all rows and cells is the most common Excel processing task -- whether you are validating import data, transforming records, or feeding a reporting pipeline. IronXL exposes a Rows collection on every WorkSheet:

using IronXL;

WorkBook workbook  = WorkBook.Load("customers.xlsx");
WorkSheet worksheet = workbook.WorkSheets[0];

Console.WriteLine($"Total rows    : {worksheet.RowCount}");
Console.WriteLine($"Total columns : {worksheet.ColumnCount}");
Console.WriteLine();

foreach (var row in worksheet.Rows)
{
    foreach (var cell in row)
    {
        if (!cell.IsEmpty)
            Console.Write($"{cell.StringValue,-20}");
    }
    Console.WriteLine();
}

The RowCount and ColumnCount properties return only the populated range -- empty trailing rows and columns are not included. Checking cell.IsEmpty before reading prevents unnecessary processing on sparse sheets.

For large files, consider using range-based access (worksheet["A1:D500"]) instead of full-sheet iteration. This limits the cells loaded into memory and speeds up processing when you only need a subset of the data.

How Do You Extract Typed Values from Cells?

Typed Property Accessors

Cells in a real-world spreadsheet contain strings, integers, decimals, booleans, and dates. IronXL exposes dedicated typed properties so you never have to parse raw strings manually:

using IronXL;

WorkBook workbook = WorkBook.Load("inventory.xlsx");
WorkSheet sheet   = workbook.GetWorkSheet("Products");

// Typed accessors handle conversion automatically
string  productName = sheet["A2"].StringValue;
int     quantity    = sheet["B2"].IntValue;
decimal unitPrice   = sheet["C2"].DecimalValue;
bool    inStock     = sheet["D2"].BoolValue;
DateTime? lastAudit = sheet["E2"].DateTimeValue;

Console.WriteLine($"Product  : {productName}");
Console.WriteLine($"Qty      : {quantity}");
Console.WriteLine($"Price    : {unitPrice:C}");
Console.WriteLine($"In Stock : {inStock}");
Console.WriteLine($"Audited  : {lastAudit?.ToString("d") ?? "Never"}");

When a cell holds a formula, IronXL evaluates it and returns the computed result through the same typed properties. You do not need to call a separate evaluation method. For cells that may be empty or contain an incompatible type, the library returns the default value for that type rather than throwing an exception, which simplifies input validation logic.

IronXL Cell Value Properties and Their Equivalent .NET Types
Property.NET TypeReturns When EmptyNotes
StringValuestringEmpty stringAlways safe; converts any cell to text
IntValueint0Truncates decimals
DecimalValuedecimal0mPreserves precision for financial data
DoubleValuedouble0.0Use for scientific or statistical values
BoolValueboolfalseReads Excel TRUE/FALSE cells
DateTimeValueDateTime?nullNullable -- check before use

How Do You Work with Multiple Named Worksheets?

Access by Name, Index, or Iteration

Enterprise spreadsheets often contain several named sheets -- one per month, one per region, or one per product line. IronXL gives you multiple ways to access them:

using IronXL;

WorkBook workbook = WorkBook.Load("annual_sales.xlsx");

// Option 1: access by name (throws if the sheet does not exist)
WorkSheet januarySheet = workbook.GetWorkSheet("January");

// Option 2: iterate all sheets in the workbook
foreach (WorkSheet ws in workbook.WorkSheets)
{
    Console.WriteLine($"Sheet: {ws.Name}  |  Rows: {ws.RowCount}");

    // Read the header row from each sheet
    string header = ws["A1"].StringValue;
    Console.WriteLine($"  Header: {header}");
}

// Option 3: access by zero-based index
WorkSheet lastSheet = workbook.WorkSheets[workbook.WorkSheets.Count - 1];
Console.WriteLine($"Last sheet: {lastSheet.Name}");

When the sheet name is known at design time, GetWorkSheet is the clearest option. For dynamic processing -- where sheet names come from user input or configuration -- iterating the WorkSheets collection prevents hard-coded assumptions and handles workbooks with varying numbers of sheets.

How Do You Handle Merged Cells and Formatted Regions?

Reports and dashboards frequently use merged cells for headings, grouped labels, and summary rows. IronXL reads the value from the top-left cell of a merged region, exactly as Excel displays it:

using IronXL;

WorkBook workbook = WorkBook.Load("report_with_merges.xlsx");
WorkSheet sheet   = workbook.DefaultWorkSheet;

// The merged region A1:D1 stores its value in cell A1
string reportTitle = sheet["A1"].StringValue;
Console.WriteLine($"Report title : {reportTitle}");

// Read cell formatting metadata
var titleCell = sheet["A1"];
Console.WriteLine($"Bold         : {titleCell.Style.Font.Bold}");
Console.WriteLine($"Font size    : {titleCell.Style.Font.Height}");

// Scan an entire column for non-empty section headers
foreach (var cell in sheet["A1:A100"])
{
    if (!cell.IsEmpty && cell.Style.Font.Bold)
        Console.WriteLine($"Section header at {cell.AddressString}: {cell.StringValue}");
}

The Style property tree mirrors the structure of the OOXML SpreadsheetML specification, so property names feel familiar if you have worked with the Open XML SDK. However, IronXL wraps all of that complexity in a clean API that does not require any XML manipulation on your part.

How Do You Import CSV Files with the Same API?

CSV files produced by database exports, CRM systems, and legacy applications can be read through the same WorkBook.Load call. IronXL infers the delimiter from the file content:

using IronXL;

// Load a comma-separated values file -- same method, same API
WorkBook csvWorkbook  = WorkBook.Load("export.csv");
WorkSheet csvSheet    = csvWorkbook.DefaultWorkSheet;

Console.WriteLine($"CSV rows loaded: {csvSheet.RowCount}");

// Process rows exactly like any other worksheet
foreach (var row in csvSheet.Rows)
{
    string id   = row[0].StringValue;
    string name = row[1].StringValue;
    Console.WriteLine($"{id,-10} {name}");
}

After loading, you can save the data as XLSX using csvWorkbook.SaveAs("output.xlsx"). This is a common pattern for CSV-to-Excel conversion pipelines -- receive a CSV file, enrich it with calculated columns or formatting, and return a formatted XLSX report to the user.

For tab-separated files or custom delimiters, use WorkBook.LoadCSV("file.tsv", fileFormat: ExcelFileFormat.TSV) to specify the format explicitly.

Supported Input File Formats in IronXL
FormatExtensionProduced ByNotes
XLSX.xlsxExcel 2007+, LibreOfficeDefault modern format; XML-based
XLS.xlsExcel 97--2003Binary format; full read/write support
ODS.odsLibreOffice, OpenOfficeOpenDocument Spreadsheet standard
CSV.csvAny applicationDelimiter auto-detected; no formatting
TSV.tsvDatabase exportsTab-delimited; specify format explicitly

How Does IronXL Compare to Microsoft.Office.Interop.Excel?

Interop, Open XML SDK, and IronXL Side by Side

The most common alternative to IronXL for Excel automation in .NET is Microsoft.Office.Interop.Excel. Understanding the trade-offs helps you choose the right tool for your project.

Microsoft Interop wraps the Excel COM object model. This means Excel must be installed on every machine that runs your code -- including web servers, build agents, and cloud VMs. COM object lifecycle management is manual: you must release every Range, Worksheet, and Workbook object explicitly, or Excel processes accumulate in the background and consume memory until the server restarts. Licensing is also a concern: the Office EULA prohibits server-side automation in many scenarios.

IronXL avoids all of these constraints. It is a pure managed library with no COM dependency. The WorkBook object is a standard .NET class; the garbage collector handles cleanup. You can run the same code on a developer laptop, an Azure App Service, a Docker container, or a Raspberry Pi running Linux.

The Open XML SDK from Microsoft is another alternative. It provides direct access to the OOXML file format without requiring Excel, but it operates at a very low level -- you manipulate XML elements directly. Reading a single cell value requires navigating shared string tables, cell references, and style indices. IronXL wraps all of that into the single-line sheet["A1"].StringValue call shown throughout this guide.

How Do You Deploy Excel Processing to Linux and Docker?

Server deployments are where IronXL's independence from Excel becomes most valuable. The same code you write on Windows runs unchanged on Ubuntu, Alpine Linux, or macOS. For containerized deployments, your Dockerfile requires no special configuration:

# Standard .NET runtime image -- no Office packages needed
FROM mcr.microsoft.com/dotnet/runtime:10.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "ExcelProcessor.dll"]
SHELL

For Azure Functions and AWS Lambda, IronXL works within the managed runtime without any additional configuration. The cold-start overhead is minimal because there is no COM initialization step.

Thread safety is built in: multiple threads can open different WorkBook instances concurrently without coordination. If you need to process thousands of files in parallel -- for example, in a background job that ingests user-uploaded spreadsheets -- you can use Parallel.ForEach or Task.WhenAll across a pool of WorkBook instances without risk of corruption.

Memory usage stays predictable because IronXL loads only the requested worksheet into memory, not the entire workbook on initialization. For very large files, this distinction matters: a workbook with ten 50MB sheets does not require 500MB of RAM just to read a single sheet. The IronXL performance documentation covers additional strategies for handling high-volume file processing scenarios.

What Are Your Next Steps?

The quickest way to validate IronXL in your project is to install the NuGet package and run the examples in this guide against a real file from your environment. A free trial license unlocks all features with no code changes required when you are ready for production.

Explore related IronXL capabilities that complement file reading:

For questions about licensing, cross-platform support, or specific file format requirements, the IronXL support team is available through live chat and email.

First Step:
arrow pointer
Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...
Read More

Related Articles

Key in blue circle

Get your free 30-day Trial Key instantly.

Your trial license will be sent to your email address

No limitations. 100% unlocked. No credit card.

bullet_checkedNo credit card or account creation requiredNo limitations. 100% unlocked. No credit card.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Book your free Live Demo
Booking Badge

Trusted by Millions of Engineers Worldwide

Iron Software's customer logos
Get Your No-Obligation Consult
Complete the form below or email sales@ironsoftware.com
Your details will always be kept confidential.
Trusted by Millions of Engineers Worldwide
Iron Software's customer logos
Get your free 30-day Trial Key instantly.
No credit card or account creation required