C#
NPOI
file handling
Excel
data processing

How to read file using NPOI

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

NPOI is a .NET library for reading and writing Microsoft Office files (Excel, Word) without requiring Office to be installed. To read an Excel file, open a FileStream, create an IWorkbook from it (using HSSFWorkbook for .xls or XSSFWorkbook for .xlsx), then iterate through sheets, rows, and cells. NPOI is the .NET port of Apache POI (Java) and works on .NET Framework, .NET Core, and .NET 5+.

Installation

bash
1# .NET CLI
2dotnet add package NPOI
3
4# Package Manager Console
5Install-Package NPOI
6
7# Or for latest version
8dotnet add package NPOI --version 2.7.1

The NPOI NuGet package includes support for both .xls (HSSF) and .xlsx (XSSF) formats.

Reading an .xlsx File (Basic)

csharp
1using NPOI.SS.UserModel;
2using NPOI.XSSF.UserModel;
3using System.IO;
4
5// Open the file
6using var stream = new FileStream("data.xlsx", FileMode.Open, FileAccess.Read);
7IWorkbook workbook = new XSSFWorkbook(stream);
8
9// Get the first sheet
10ISheet sheet = workbook.GetSheetAt(0);
11
12// Iterate through rows
13for (int rowIndex = 0; rowIndex <= sheet.LastRowNum; rowIndex++)
14{
15    IRow row = sheet.GetRow(rowIndex);
16    if (row == null) continue;  // Skip empty rows
17
18    for (int colIndex = 0; colIndex < row.LastCellNum; colIndex++)
19    {
20        ICell cell = row.GetCell(colIndex);
21        Console.Write($"{GetCellValue(cell)}\t");
22    }
23    Console.WriteLine();
24}

Reading an .xls File

csharp
1using NPOI.HSSF.UserModel;
2using NPOI.SS.UserModel;
3using System.IO;
4
5// .xls files use HSSFWorkbook
6using var stream = new FileStream("data.xls", FileMode.Open, FileAccess.Read);
7IWorkbook workbook = new HSSFWorkbook(stream);
8
9ISheet sheet = workbook.GetSheetAt(0);
10// Rest is identical — use IWorkbook/ISheet interfaces

Auto-Detecting File Format

csharp
1using NPOI.SS.UserModel;
2using NPOI.HSSF.UserModel;
3using NPOI.XSSF.UserModel;
4using System.IO;
5
6IWorkbook OpenWorkbook(string filePath)
7{
8    using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
9
10    if (Path.GetExtension(filePath).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
11        return new XSSFWorkbook(stream);
12    else
13        return new HSSFWorkbook(stream);
14}
15
16// Or use WorkbookFactory (auto-detects format)
17using var stream = new FileStream("data.xlsx", FileMode.Open, FileAccess.Read);
18IWorkbook workbook = WorkbookFactory.Create(stream);

WorkbookFactory.Create() examines the file header and creates the correct workbook type automatically.

Handling Cell Types

csharp
1string GetCellValue(ICell cell)
2{
3    if (cell == null) return string.Empty;
4
5    switch (cell.CellType)
6    {
7        case CellType.String:
8            return cell.StringCellValue;
9
10        case CellType.Numeric:
11            // Check if it is a date
12            if (DateUtil.IsCellDateFormatted(cell))
13                return cell.DateCellValue.ToString("yyyy-MM-dd");
14            return cell.NumericCellValue.ToString();
15
16        case CellType.Boolean:
17            return cell.BooleanCellValue.ToString();
18
19        case CellType.Formula:
20            // Evaluate the formula and return the result
21            return cell.CellType == CellType.Numeric
22                ? cell.NumericCellValue.ToString()
23                : cell.StringCellValue;
24
25        case CellType.Blank:
26            return string.Empty;
27
28        default:
29            return cell.ToString();
30    }
31}

Always check CellType before accessing cell values. Accessing StringCellValue on a numeric cell throws an exception.

Reading with Headers (Dictionary per Row)

csharp
1List<Dictionary<string, string>> ReadExcelAsRecords(string filePath)
2{
3    using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
4    IWorkbook workbook = WorkbookFactory.Create(stream);
5    ISheet sheet = workbook.GetSheetAt(0);
6
7    // First row is headers
8    IRow headerRow = sheet.GetRow(0);
9    var headers = new List<string>();
10    for (int i = 0; i < headerRow.LastCellNum; i++)
11    {
12        headers.Add(GetCellValue(headerRow.GetCell(i)));
13    }
14
15    // Read data rows
16    var records = new List<Dictionary<string, string>>();
17    for (int rowIndex = 1; rowIndex <= sheet.LastRowNum; rowIndex++)
18    {
19        IRow row = sheet.GetRow(rowIndex);
20        if (row == null) continue;
21
22        var record = new Dictionary<string, string>();
23        for (int colIndex = 0; colIndex < headers.Count; colIndex++)
24        {
25            record[headers[colIndex]] = GetCellValue(row.GetCell(colIndex));
26        }
27        records.Add(record);
28    }
29
30    return records;
31}
32
33// Usage
34var data = ReadExcelAsRecords("employees.xlsx");
35foreach (var row in data)
36{
37    Console.WriteLine($"Name: {row["Name"]}, Age: {row["Age"]}");
38}

Reading a Specific Sheet by Name

csharp
1ISheet sheet = workbook.GetSheet("Sales Data");
2if (sheet == null)
3{
4    Console.WriteLine("Sheet 'Sales Data' not found");
5    // List available sheets
6    for (int i = 0; i < workbook.NumberOfSheets; i++)
7    {
8        Console.WriteLine($"  Sheet {i}: {workbook.GetSheetName(i)}");
9    }
10}

Evaluating Formulas

csharp
1using NPOI.SS.UserModel;
2
3IFormulaEvaluator evaluator = workbook.GetCreationHelper().CreateFormulaEvaluator();
4
5ICell cell = sheet.GetRow(0).GetCell(0);
6if (cell.CellType == CellType.Formula)
7{
8    CellValue evaluated = evaluator.Evaluate(cell);
9    switch (evaluated.CellType)
10    {
11        case CellType.Numeric:
12            Console.WriteLine(evaluated.NumberValue);
13            break;
14        case CellType.String:
15            Console.WriteLine(evaluated.StringValue);
16            break;
17        case CellType.Boolean:
18            Console.WriteLine(evaluated.BooleanValue);
19            break;
20    }
21}

Use IFormulaEvaluator to compute formula results. Without evaluation, formula cells return the formula text, not the computed value.

Reading into a DataTable

csharp
1using System.Data;
2
3DataTable ExcelToDataTable(string filePath)
4{
5    using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
6    IWorkbook workbook = WorkbookFactory.Create(stream);
7    ISheet sheet = workbook.GetSheetAt(0);
8
9    var table = new DataTable(sheet.SheetName);
10
11    // Create columns from header row
12    IRow headerRow = sheet.GetRow(0);
13    for (int i = 0; i < headerRow.LastCellNum; i++)
14    {
15        table.Columns.Add(GetCellValue(headerRow.GetCell(i)));
16    }
17
18    // Add data rows
19    for (int rowIndex = 1; rowIndex <= sheet.LastRowNum; rowIndex++)
20    {
21        IRow row = sheet.GetRow(rowIndex);
22        if (row == null) continue;
23
24        DataRow dataRow = table.NewRow();
25        for (int colIndex = 0; colIndex < table.Columns.Count; colIndex++)
26        {
27            dataRow[colIndex] = GetCellValue(row.GetCell(colIndex));
28        }
29        table.Rows.Add(dataRow);
30    }
31
32    return table;
33}

Common Pitfalls

  • Not disposing the FileStream: Forgetting using on the FileStream leaves the file locked. Always use using var stream = ... or explicitly call stream.Dispose() to release the file handle.
  • Null rows and cells: Empty rows return null from GetRow(), and empty cells return null from GetCell(). Always check for null before accessing properties, or use GetCell(index, MissingCellPolicy.CREATE_NULL_AS_BLANK).
  • Wrong workbook type: Using XSSFWorkbook for a .xls file (or HSSFWorkbook for .xlsx) throws an exception. Use WorkbookFactory.Create() to auto-detect, or check the file extension.
  • Date cells appear as numbers: Excel stores dates as numeric values. Use DateUtil.IsCellDateFormatted(cell) to check if a numeric cell is actually a date before reading it.
  • Large files and memory: NPOI loads the entire workbook into memory. For very large .xlsx files (100MB+), consider using the SAX-based event model (XSSFReader) or stream-based reading to reduce memory usage.

Summary

  • Use XSSFWorkbook for .xlsx and HSSFWorkbook for .xls, or WorkbookFactory.Create() for auto-detection
  • Always check CellType before accessing cell values — mismatched access throws exceptions
  • Use DateUtil.IsCellDateFormatted() to distinguish dates from numbers
  • Use IFormulaEvaluator to compute formula cell results
  • Check for null rows and cells when iterating — Excel files often have gaps
  • Dispose FileStream properly with using to avoid file locks

Course illustration
Course illustration

All Rights Reserved.