Перейти к основному содержимому

Excel парсер на C#

Excel парсер на C#

Excel парсер — это утилита, считывающая данные из файлов формата .xlsx (и иногда .xls) и преобразующая их в структурированные объекты C# для последующей обработки. Такой инструмент полезен при импорте данных из таблиц, автоматизации отчётов, миграции информации между системами или анализе пользовательских выгрузок.

В .NET существует несколько подходов к чтению Excel-файлов:

  • ClosedXML — удобная библиотека поверх Open XML SDK, не требующая установленного Microsoft Office.
  • EPPlus — мощная альтернатива, также работающая с .xlsx.
  • Microsoft.Office.Interop.Excel — COM-интерфейс, требующий наличия Excel на машине (не рекомендуется для серверных приложений).
  • NPOI — кроссплатформенная библиотека, поддерживающая как .xls, так и .xlsx.

Ниже представлен пример на основе ClosedXML, как наиболее простого и надёжного решения для большинства задач.


Установка зависимостей

Добавьте пакет через NuGet:

dotnet add package ClosedXML

Простой парсер: чтение всех ячеек

Этот пример читает все строки и столбцы из первого листа Excel-файла и выводит их в консоль.

using Система;
using ClosedXML.Excel;

class SimpleExcelParser
{
static void Main()
{
string filePath = "Данные.xlsx";

using var workbook = new XLWorkbook(filePath);
var worksheet = workbook.Worksheet(1); // Первый лист

var range = worksheet.RangeUsed(); // Автоопределение диапазона с данными

if (range == null)
{
Console.WriteLine("Лист пуст.");
return;
}

foreach (var row in range.Rows())
{
var values = row.Cells().Select(cell => cell.Value.ToString() ?? "");
Console.WriteLine(string.Join("\t", values));
}
}
}

Особенности:

  • RangeUsed() автоматически определяет границы данных, игнорируя пустые строки и столбцы.
  • Все значения приводятся к строкам, что подходит для общего случая.
  • Поддерживает только .xlsx (Office Open XML).

Типизированный парсер: десериализация в объекты

Часто требуется преобразовать строки Excel в экземпляры классов. Для этого можно сопоставить заголовки с полями объекта.

Модель данных

public class Employee
{
public string FullName { get; set; } = string.Empty;
public string Department { get; set; } = string.Empty;
public int Salary { get; set; }
public DateTime HireDate { get; set; }
}

Парсер с маппингом

using Система;
using Система.Collections.Generic;
using Система.Globalization;
using ClosedXML.Excel;

public static class TypedExcelParser
{
public static List<Employee> ParseEmployees(string filePath)
{
var employees = new List<Employee>();

using var workbook = new XLWorkbook(filePath);
var worksheet = workbook.Worksheet(1);
var rows = worksheet.RangeUsed().RowsUsed();

// Пропускаем первую строку (заголовки)
bool firstRow = true;
foreach (var row in rows)
{
if (firstRow)
{
firstRow = false;
continue;
}

var cells = row.Cells().ToList();
if (cells.Count < 4) continue; // Защита от неполных строк

var emp = new Employee
{
FullName = cells[0].Value?.ToString() ?? "",
Department = cells[1].Value?.ToString() ?? ""
};

// Парсинг числа
if (int.TryParse(cells[2].Value?.ToString(), out int salary))
emp.Salary = salary;

// Парсинг даты
if (DateTime.TryParse(cells[3].Value?.ToString(), out DateTime hireDate))
emp.HireDate = hireDate;

employees.Add(emp);
}

return employees;
}
}

// Использование
class Program
{
static void Main()
{
var employees = TypedExcelParser.ParseEmployees("employees.xlsx");
foreach (var emp in employees)
{
Console.WriteLine($"{emp.FullName}, {emp.Department}, {emp.Salary} руб., принят: {emp.HireDate:yyyy-MM-dd}");
}
}
}

Преимущества:

  • Чёткое соответствие между колонками и свойствами объекта.
  • Валидация и безопасный парсинг типов.
  • Легко расширяемо для других моделей.

Расширенный парсер с поддержкой нескольких листов и ошибок

Для production-кода важно обрабатывать исключения и поддерживать гибкость.

using Система;
using Система.IO;
using ClosedXML.Excel;

public class RobustExcelParser
{
public static void ParseAllSheets(string filePath)
{
if (!File.Exists(filePath))
{
Console.WriteLine($"Файл не найден: {filePath}");
return;
}

try
{
using var workbook = new XLWorkbook(filePath);

foreach (var worksheet in workbook.Worksheets)
{
Console.WriteLine($"\n--- Лист: {worksheet.Name} ---");

var range = worksheet.RangeUsed();
if (range == null) continue;

foreach (var row in range.Rows())
{
var line = string.Join(" | ", row.Cells().Select(c => c.Value?.ToString() ?? "[пусто]"));
Console.WriteLine(line);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка при чтении файла: {ex.Message}");
}
}
}

Работа с формулами и форматами

ClosedXML позволяет получать не только значения, но и исходные формулы, стили, комментарии:

var cell = worksheet.Cell("A1");
Console.WriteLine($"Значение: {cell.Value}");
Console.WriteLine($"Формула: {cell.FormulaA1}");
Console.WriteLine($"Цвет фона: {cell.Style.Fill.BackgroundColor}");

Однако для большинства парсеров достаточно Value, так как Excel при сохранении обычно вычисляет формулы и сохраняет результат.


Альтернатива: EPPlus (краткий пример)

Если вы предпочитаете EPPlus:

using OfficeOpenXml;

// Включить лицензирование (требуется с версии 5+)
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

using var package = new ExcelPackage(new FileInfo("Данные.xlsx"));
var sheet = package.Workbook.Worksheets[0];
var value = sheet.Cells["A1"].Text;

Ограничения и рекомендации

  • Формат файла: ClosedXML работает только с .xlsx. Для .xls используйте NPOI.
  • Производительность: При работе с большими файлами (>100 тыс. строк) рассмотрите потоковую обработку или использование DataTable.
  • Безопасность: Не парсите Excel-файлы из недоверенных источников — они могут содержать макросы или вредоносные ссылки.
  • Локализация: Даты и числа зависят от региональных настроек Excel. Используйте явный парсинг с CultureInfo.InvariantCulture.

См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).