Skip to footer content
USING IRONXL

Best Way to Read Excel Files in C# | IronXL Step-by-Step Guide

Reading Excel files in C# is a common challenge for .NET developers. Whether you are building a data import pipeline, a reporting tool, or a batch-processing system, parsing spreadsheet data cleanly matters. IronXL is a .NET library that handles XLSX, XLS, and CSV files without requiring Microsoft Office or COM Interop on the server. This guide walks through the complete workflow -- from installation to advanced queries -- so you can choose the right approach for your project.

Get stated with IronXL now.
green arrow pointer

What Is the Best Way to Read Excel Files in C#?

The best approach is to use a dedicated, Office-independent library such as IronXL. Traditional methods like Microsoft.Office.Interop.Excel work on machines where Excel is installed, but they are brittle in server or container environments because they spin up a COM process behind the scenes. OpenXML SDK is free and server-safe, but it exposes a low-level XML model that requires significant boilerplate for everyday tasks.

IronXL sits between these extremes. The API mirrors how developers already think about spreadsheets -- workbooks contain worksheets, worksheets contain cells, and cells hold typed values. The library handles format detection, formula evaluation, and encoding internally, so you spend time on business logic rather than parsing details.

Excel Reading Approaches in C# Compared
Approach Requires Office? Server Safe? API Simplicity Format Support
COM Interop Yes No Low XLSX, XLS
OpenXML SDK No Yes Low XLSX only
IronXL No Yes High XLSX, XLS, CSV

The IronXL Excel reading documentation covers the full API surface. For now, the sections below show the core patterns you will use on every project.

How Do You Install IronXL in a .NET Project?

Installation takes under a minute using the NuGet Package Manager. Open a terminal in your project directory and run:

dotnet add package IronXL.Excel
dotnet add package IronXL.Excel
SHELL

Alternatively, use the Visual Studio Package Manager Console:

Install-Package IronXL.Excel
Install-Package IronXL.Excel
SHELL

After installation, add the using IronXL; directive to any file that needs spreadsheet access. The library targets .NET 10, .NET 8, .NET 6, .NET Framework 4.6.2, and .NET Standard 2.0, so it fits into existing projects without upgrading the runtime. See the IronXL installation guide for platform-specific notes and NuGet package details.

No additional runtime components, registry entries, or Office licenses are required. The NuGet package bundles everything the library needs.

Verifying the Installation

After adding the package, build the project once to confirm the reference resolves correctly. If you see a CS0246 error for IronXL types, check that the using IronXL; directive is present and that the target framework in your .csproj is one of the supported versions. The IronXL compatibility matrix lists all confirmed runtime targets.

How Do You Load and Read an Excel Workbook?

Loading a workbook requires a single method call. WorkBook.Load accepts a file path and returns a WorkBook object that represents the entire file in memory.

using IronXL;

// Load any supported format -- XLSX, XLS, or CSV
WorkBook workbook = WorkBook.Load("financial_report.xlsx");

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

// Or retrieve a named worksheet
WorkSheet expenses = workbook.GetWorkSheet("Expenses");

Console.WriteLine($"Sheets loaded: {workbook.WorkSheets.Count}");
Console.WriteLine($"Default sheet rows: {worksheet.RowCount}");
using IronXL;

// Load any supported format -- XLSX, XLS, or CSV
WorkBook workbook = WorkBook.Load("financial_report.xlsx");

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

// Or retrieve a named worksheet
WorkSheet expenses = workbook.GetWorkSheet("Expenses");

Console.WriteLine($"Sheets loaded: {workbook.WorkSheets.Count}");
Console.WriteLine($"Default sheet rows: {worksheet.RowCount}");
$vbLabelText   $csharpLabel

Best Way to Read Excel File in C# with IronXL: Image 1 - Console output for confirmation of loaded workbook

The WorkBook object keeps all worksheet data accessible. Each WorkSheet instance maps to a tab in the file. Accessing by index (WorkSheets[0]) is reliable for single-sheet files; accessing by name is safer when the file contains multiple tabs with known names.

IronXL evaluates formulas automatically when you read a cell. If cell B10 contains =SUM(B2:B9), reading sheet["B10"].DecimalValue returns the calculated total, not the formula string. For more details on workbook loading options, see the load spreadsheet how-to guide.

Working with Multiple Worksheets

When a workbook contains several tabs, you can enumerate them using workbook.WorkSheets and process each one in turn. This is useful for files that split data by month, department, or region across separate tabs. The WorkSheet.Name property gives you the tab label as a string, which you can use for conditional processing or logging.

How Do You Read Cell Values from a Worksheet?

IronXL provides strongly-typed properties on each cell so you can read values directly into the correct .NET type without manual parsing.

using IronXL;

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

// Address-based access with typed properties
string productName = sheet["A2"].StringValue;
int quantity       = sheet["B2"].IntValue;
decimal price      = sheet["C2"].DecimalValue;
bool inStock       = sheet["D2"].BoolValue;

// Check for empty cells before processing
var statusCell = sheet["E2"];
if (statusCell.Value != null && statusCell.StringValue.Length > 0)
{
    Console.WriteLine($"Status: {statusCell.StringValue}");
}

// Row/column index access (zero-based)
var firstDataCell = sheet.Rows[1].Columns[0];
Console.WriteLine($"Product: {productName}, Qty: {quantity}, Price: {price:C}");
using IronXL;

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

// Address-based access with typed properties
string productName = sheet["A2"].StringValue;
int quantity       = sheet["B2"].IntValue;
decimal price      = sheet["C2"].DecimalValue;
bool inStock       = sheet["D2"].BoolValue;

// Check for empty cells before processing
var statusCell = sheet["E2"];
if (statusCell.Value != null && statusCell.StringValue.Length > 0)
{
    Console.WriteLine($"Status: {statusCell.StringValue}");
}

// Row/column index access (zero-based)
var firstDataCell = sheet.Rows[1].Columns[0];
Console.WriteLine($"Product: {productName}, Qty: {quantity}, Price: {price:C}");
$vbLabelText   $csharpLabel

Best Way to Read Excel File in C# with IronXL: Image 2 - Simple Excel read output with IronXL

The sheet["A2"] syntax uses standard Excel notation. Column letters are case-insensitive, and row numbers start at 1, matching how Excel labels cells. The cell value reading documentation shows additional typed accessors including DateTimeValue for cells formatted as dates.

When a cell contains a number stored as text (a common data-quality problem in exported spreadsheets), StringValue returns the text as-is while DecimalValue attempts a parse and returns 0 on failure. Always validate unexpected data before treating it as a typed value in production code.

Handling Date and Boolean Cells

Date cells in Excel are stored internally as serial numbers. IronXL exposes DateTimeValue to convert them into a .NET DateTime object without manual arithmetic. For cells containing TRUE or FALSE, BoolValue returns the correct boolean without string comparison. These typed accessors eliminate a class of data-type bugs that commonly appear when reading spreadsheets through generic text-based parsers.

How Do You Iterate Through Rows and Cells?

Iterating through a dataset requires a range or a row collection. IronXL supports both approaches, and you can combine them to match the shape of the data.

using IronXL;

WorkBook workbook = WorkBook.Load("financial_report.xlsx");
WorkSheet sheet = workbook.WorkSheets[0];

// Iterate a cell range -- skips header row
foreach (var cell in sheet["A2:D100"])
{
    Console.WriteLine($"{cell.AddressString}: {cell.Text}");
}

// Row-by-row with column access
for (int rowIndex = 1; rowIndex < sheet.RowCount; rowIndex++)
{
    var row = sheet.Rows[rowIndex];
    var values = new System.Text.StringBuilder();

    foreach (var cell in row)
    {
        if (cell.Value != null)
            values.Append($"{cell.StringValue}\t");
    }

    Console.WriteLine(values.ToString().TrimEnd());
}
using IronXL;

WorkBook workbook = WorkBook.Load("financial_report.xlsx");
WorkSheet sheet = workbook.WorkSheets[0];

// Iterate a cell range -- skips header row
foreach (var cell in sheet["A2:D100"])
{
    Console.WriteLine($"{cell.AddressString}: {cell.Text}");
}

// Row-by-row with column access
for (int rowIndex = 1; rowIndex < sheet.RowCount; rowIndex++)
{
    var row = sheet.Rows[rowIndex];
    var values = new System.Text.StringBuilder();

    foreach (var cell in row)
    {
        if (cell.Value != null)
            values.Append($"{cell.StringValue}\t");
    }

    Console.WriteLine(values.ToString().TrimEnd());
}
$vbLabelText   $csharpLabel

Best Way to Read Excel File in C# with IronXL: Image 3 - Output for iterating through rows

The range string "A2:D100" creates a flat cell collection. Rows within the range are processed top-to-bottom, left-to-right. This pattern works well for exporting to a List<T>, a DataTable, or a database.

The sheet.RowCount property reflects the last used row in the worksheet, so the loop terminates automatically when the data ends. The iterate Excel range guide covers additional iteration patterns including column-first traversal.

Skipping Header Rows

Most spreadsheets have a header row that describes column names rather than containing data. Start range iteration at row 2 (e.g., "A2:D100") or begin the index loop at rowIndex = 1 to skip the header. If you use ToDataTable(true), IronXL handles header detection automatically and maps column names from the first row.

How Do You Handle Multiple Excel Formats?

IronXL detects the file format from the extension and file header automatically. The API is identical for XLSX, XLS, and CSV files, which means the same parsing code works across all three formats without conditional logic.

using IronXL;

// Load different formats with identical API
WorkBook xlsxBook = WorkBook.Load("Modern.xlsx");
WorkBook xlsBook  = WorkBook.Load("Legacy.xls");
WorkBook csvBook  = WorkBook.Load("Export.csv");

// Access worksheets identically across formats
WorkSheet sheet1 = xlsxBook.DefaultWorkSheet;
WorkSheet sheet2 = xlsBook.DefaultWorkSheet;
WorkSheet sheet3 = csvBook.DefaultWorkSheet;

// Cross-format conversion -- save XLSX as CSV, or CSV as XLSX
xlsxBook.SaveAs("converted_output.csv");
csvBook.SaveAs("structured_output.xlsx");

Console.WriteLine($"XLSX rows: {sheet1.RowCount}");
Console.WriteLine($"XLS rows:  {sheet2.RowCount}");
Console.WriteLine($"CSV rows:  {sheet3.RowCount}");
using IronXL;

// Load different formats with identical API
WorkBook xlsxBook = WorkBook.Load("Modern.xlsx");
WorkBook xlsBook  = WorkBook.Load("Legacy.xls");
WorkBook csvBook  = WorkBook.Load("Export.csv");

// Access worksheets identically across formats
WorkSheet sheet1 = xlsxBook.DefaultWorkSheet;
WorkSheet sheet2 = xlsBook.DefaultWorkSheet;
WorkSheet sheet3 = csvBook.DefaultWorkSheet;

// Cross-format conversion -- save XLSX as CSV, or CSV as XLSX
xlsxBook.SaveAs("converted_output.csv");
csvBook.SaveAs("structured_output.xlsx");

Console.WriteLine($"XLSX rows: {sheet1.RowCount}");
Console.WriteLine($"XLS rows:  {sheet2.RowCount}");
Console.WriteLine($"CSV rows:  {sheet3.RowCount}");
$vbLabelText   $csharpLabel

For CSV files, IronXL respects RFC 4180 conventions including quoted fields that contain commas, newlines inside quoted values, and escaped double-quotes. The CSV to XLSX conversion guide covers delimiter customisation for non-standard CSV exports.

When your application must accept files from external systems, it is good practice to inspect the file extension and validate the content before loading. IronXL throws a descriptive exception if the file is corrupt or an unsupported format, which you can catch and surface to the user.

How Do You Run Advanced Queries on Excel Data?

Beyond cell-by-cell reading, IronXL exposes aggregate functions and LINQ compatibility that turn a worksheet range into a queryable collection.

using IronXL;
using System.Linq;

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

// Built-in aggregates -- no manual looping needed
decimal totalSales = sheet["B2:B50"].Sum();
decimal maxRevenue = sheet["C2:C50"].Max(c => c.DecimalValue);
decimal avgMargin  = sheet["D2:D50"].Avg();

// LINQ filtering directly on a range
var highValueRows = sheet["C2:C50"]
    .Where(c => c.DecimalValue > 1000)
    .Select(c => new { c.AddressString, c.DecimalValue });

foreach (var row in highValueRows)
    Console.WriteLine($"High value at {row.AddressString}: {row.DecimalValue:C}");

// Write a calculated result back to the sheet
sheet["E2"].Value = totalSales;
workbook.SaveAs("Financials_Updated.xlsx");

Console.WriteLine($"Total: {totalSales:C}, Max: {maxRevenue:C}, Avg: {avgMargin:C}");
using IronXL;
using System.Linq;

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

// Built-in aggregates -- no manual looping needed
decimal totalSales = sheet["B2:B50"].Sum();
decimal maxRevenue = sheet["C2:C50"].Max(c => c.DecimalValue);
decimal avgMargin  = sheet["D2:D50"].Avg();

// LINQ filtering directly on a range
var highValueRows = sheet["C2:C50"]
    .Where(c => c.DecimalValue > 1000)
    .Select(c => new { c.AddressString, c.DecimalValue });

foreach (var row in highValueRows)
    Console.WriteLine($"High value at {row.AddressString}: {row.DecimalValue:C}");

// Write a calculated result back to the sheet
sheet["E2"].Value = totalSales;
workbook.SaveAs("Financials_Updated.xlsx");

Console.WriteLine($"Total: {totalSales:C}, Max: {maxRevenue:C}, Avg: {avgMargin:C}");
$vbLabelText   $csharpLabel

Best Way to Read Excel File in C# with IronXL: Image 4 - Advanced Reading Operations Console Output

LINQ compatibility is useful when you need to filter rows before importing them into a database or validate that all values in a column meet a threshold. The library evaluates formulas before LINQ runs, so aggregate queries always operate on final computed values rather than formula strings.

The LINQ with IronXL tutorial covers joining worksheets, grouping by column, and projecting results into strongly-typed objects -- patterns that eliminate a lot of boilerplate in data-pipeline code.

How Do You Export Excel Data to a DataTable?

Many .NET applications load spreadsheet data into an ADO.NET DataTable for further processing or database insertion. IronXL provides a direct conversion method that removes the need for manual column mapping.

using IronXL;
using System.Data;

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

// Convert worksheet to DataTable -- first row becomes column headers
DataTable dataTable = sheet.ToDataTable(true);

Console.WriteLine($"Columns: {dataTable.Columns.Count}");
Console.WriteLine($"Rows:    {dataTable.Rows.Count}");

// Iterate the DataTable normally
foreach (DataRow row in dataTable.Rows)
{
    Console.WriteLine($"{row["ProductName"]} -- {row["Quantity"]} -- {row["Price"]}");
}
using IronXL;
using System.Data;

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

// Convert worksheet to DataTable -- first row becomes column headers
DataTable dataTable = sheet.ToDataTable(true);

Console.WriteLine($"Columns: {dataTable.Columns.Count}");
Console.WriteLine($"Rows:    {dataTable.Rows.Count}");

// Iterate the DataTable normally
foreach (DataRow row in dataTable.Rows)
{
    Console.WriteLine($"{row["ProductName"]} -- {row["Quantity"]} -- {row["Price"]}");
}
$vbLabelText   $csharpLabel

Passing true to ToDataTable treats the first worksheet row as column headers. The resulting DataTable uses string column names that match the header text, making subsequent LINQ-to-DataSet queries readable. The DataTable export documentation covers null-handling and type inference options.

This pattern is particularly useful when the downstream code already expects a DataTable -- for example, when calling SqlBulkCopy to insert rows into SQL Server. You can load the XLSX file, convert it to a DataTable, and bulk-insert without writing any column-mapping boilerplate.

IronXL Core Reading API Reference
Operation API Returns
Load file WorkBook.Load(path) WorkBook
Get worksheet by index workbook.WorkSheets[0] WorkSheet
Get worksheet by name workbook.GetWorkSheet("name") WorkSheet
Read string cell sheet["A1"].StringValue string
Read decimal cell sheet["B1"].DecimalValue decimal
Iterate range foreach cell in sheet["A2:D100"] IEnumerable<Cell>
Sum a range sheet["B2:B50"].Sum() decimal
Export to DataTable sheet.ToDataTable(true) DataTable

For a complete API listing, see the IronXL API reference. The reference covers every property and method with parameter descriptions and return type details.

What Are Your Next Steps?

Reading Excel files in C# is straightforward once you have the right library. IronXL removes the Office dependency, simplifies the API surface, and handles XLSX, XLS, and CSV formats with the same code path. The patterns covered here -- loading a workbook, reading typed cell values, iterating ranges, running aggregates, and exporting to a DataTable -- cover the majority of real-world spreadsheet-reading requirements.

To continue building on these patterns:

For teams evaluating IronXL against other libraries, the IronXL vs EPPlus comparison and the IronXL vs NPOI comparison cover performance benchmarks and API differences. Both comparisons include code samples for equivalent operations in each library.

Microsoft's own Excel file format specification is a useful reference if you encounter unusual spreadsheet structures from legacy systems. The ECMA-376 standard defines the OOXML format that XLSX files follow.

Start with a free IronXL trial license to test the full API in your own project before committing to a production license.

Frequently Asked Questions

What is the best way to read Excel files in C#?

The best way to read Excel files in C# is to use a dedicated, Office-independent library such as IronXL. It handles XLSX, XLS, and CSV formats without requiring Microsoft Excel or COM Interop, making it safe for server and container environments.

Do you need Microsoft Office installed to use IronXL?

No. IronXL is a standalone .NET library distributed as a NuGet package. It does not require Microsoft Office, Excel, or any COM components on the machine.

What Excel file formats does IronXL support?

IronXL reads and writes XLSX, XLS, and CSV files. Format detection is automatic based on the file extension and content header.

How do you install IronXL in a .NET project?

Run 'dotnet add package IronXL.Excel' in the terminal or 'Install-Package IronXL.Excel' in the Visual Studio Package Manager Console.

Can IronXL export Excel data to a DataTable?

Yes. The WorkSheet.ToDataTable(true) method converts any worksheet into an ADO.NET DataTable, with the first row used as column headers when true is passed.

Does IronXL support LINQ queries on Excel data?

Yes. IronXL cell ranges implement IEnumerable, so you can use LINQ methods like Where, Select, Sum, Max, and Avg directly on worksheet ranges.

How does IronXL handle Excel formulas?

IronXL evaluates formulas automatically when you read a cell value. Reading sheet["B10"].DecimalValue on a formula cell returns the computed result, not the formula string.

Which .NET versions does IronXL support?

IronXL supports .NET 10, .NET 8, .NET 6, .NET Framework 4.6.2, and .NET Standard 2.0.

Jordi Bardia
Software Engineer
Jordi is most proficient in Python, C# and C++, when he isn’t leveraging his skills at Iron Software; he’s game programming. Sharing responsibilities for product testing, product development and research, Jordi adds immense value to continual product improvement. The varied experience keeps him challenged and engaged, and he ...
Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me