如何在未安装 Excel 的情况下使用 C# 读取 OpenOffice Excel 文件
使用正确的库,在 C# 中读取和处理 OpenDocument Spreadsheet (ODS) 和 Excel 文件非常简单。 使用 IronXL,您可以通过调用一个方法将任何XLS、XLSX、ODS或CSV文件加载到WorkBook对象中——无需安装Microsoft Excel,不需要COM注册,也没有Interop麻烦。 本指南将引导您完成每个步骤:安装软件包、加载文件、提取键入的单元格值、使用命名工作表、处理合并单元格以及部署到 Linux 或容器化环境。
如何在.NET项目中安装IronXL ?
NuGet包管理器安装
通过NuGet包管理器将IronXL添加到您的项目中。 在 Visual Studio 中打开软件包管理器控制台并运行:
Install-Package IronXL.Excel
IronXL支持.NET 8、.NET 9、.NET 10、.NET Framework 4.6.2+和.NET Standard 2.0,因此适用于现代和传统代码库。安装包后,在处理电子表格的任何文件顶部添加using IronXL;指令,随后就可以加载您的第一个工作簿。
对于 Azure Functions、Docker 容器或 Linux 托管的 API,无需额外的运行时配置。 该库内部包含了所需的一切,无需调用 Excel 自动化组件。
如何在C#中加载OpenOffice或Excel文件?
IronXL通过WorkBook.Load方法将ODS、XLS、XLSX和CSV文件视为相同。 你可以传递绝对或相对文件路径,库会从文件头(而不仅仅是扩展名)检测文件格式。 这意味着从 .ods 重命名为 .xlsx 的文件仍能被正确读取。
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}");
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}");
Imports IronXL
' Load an OpenDocument Spreadsheet (.ods) produced by LibreOffice Calc or OpenOffice
Dim workbook As WorkBook = WorkBook.Load("quarterly_report.ods")
' Access the first worksheet by index
Dim sheet As WorkSheet = workbook.WorkSheets(0)
' Read a cell value
Dim companyName As String = sheet("A1").StringValue
Dim recordCount As Integer = sheet("B1").IntValue
Console.WriteLine($"Company : {companyName}")
Console.WriteLine($"Records : {recordCount}")
同样的调用方法也适用于 XLSX 和 XLS 文件——只需更改路径即可。 WorkBook.Load无论源格式如何都返回相同的强类型对象,因此无论文件源自Microsoft Excel、LibreOffice还是任何其他符合ODF的应用程序,代码的其余部分都保持不变。
如何读取工作表中的每一行和每一单元格?
遍历行集合
遍历所有行和单元格是最常见的Excel处理任务——无论您是在验证导入数据、转换记录还是提供报告管道。IronXL 在每个 WorkSheet 上都公开一个 Rows 集合:
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();
}
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();
}
Imports IronXL
Dim workbook As WorkBook = WorkBook.Load("customers.xlsx")
Dim worksheet As WorkSheet = workbook.WorkSheets(0)
Console.WriteLine($"Total rows : {worksheet.RowCount}")
Console.WriteLine($"Total columns : {worksheet.ColumnCount}")
Console.WriteLine()
For Each row In worksheet.Rows
For Each cell In row
If Not cell.IsEmpty Then
Console.Write($"{cell.StringValue,-20}")
End If
Next
Console.WriteLine()
Next
RowCount 和 ColumnCount 属性仅返回填充的范围——不包括空的尾行和列。 在读取之前检查cell.IsEmpty可防止在稀疏表上进行不必要的处理。
对于大文件,考虑使用基于范围的访问(worksheet["A1:D500"])而不是全表迭代。 这样可以限制加载到内存中的单元格数量,并在只需要部分数据时加快处理速度。
如何从单元格中提取已输入的值?
类型化属性访问器
现实世界中的电子表格单元格包含字符串、整数、小数、布尔值和日期。 IronXL公开了专用的类型化属性,因此您无需手动解析原始字符串:
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"}");
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"}");
Imports IronXL
Dim workbook As WorkBook = WorkBook.Load("inventory.xlsx")
Dim sheet As WorkSheet = workbook.GetWorkSheet("Products")
' Typed accessors handle conversion automatically
Dim productName As String = sheet("A2").StringValue
Dim quantity As Integer = sheet("B2").IntValue
Dim unitPrice As Decimal = sheet("C2").DecimalValue
Dim inStock As Boolean = sheet("D2").BoolValue
Dim lastAudit As DateTime? = sheet("E2").DateTimeValue
Console.WriteLine($"Product : {productName}")
Console.WriteLine($"Qty : {quantity}")
Console.WriteLine($"Price : {unitPrice:C}")
Console.WriteLine($"In Stock : {inStock}")
Console.WriteLine($"Audited : {If(lastAudit?.ToString("d"), "Never")}")
当单元格包含公式时, IronXL会对其进行计算,并通过相同的类型属性返回计算结果。 您无需调用单独的评估方法。 对于可能为空或包含不兼容类型的单元格,该库会返回该类型的默认值,而不是抛出异常,从而简化输入验证逻辑。
| 属性 | .NET类型 | 返回空值 | 注意事项 |
|---|---|---|---|
StringValue |
string |
空字符串 | 始终安全;可将任何单元格转换为文本 |
IntValue |
int |
0 |
截断小数 |
DecimalValue |
decimal |
0m |
保持财务数据的精确性 |
DoubleValue |
double |
0.0 |
用于科学或统计值 |
BoolValue |
bool |
false |
读取 Excel 中的 TRUE/FALSE 单元格 |
DateTimeValue |
DateTime? |
null |
可空——使用前请检查 |
如何处理多个已命名的工作表?
按名称、索引或迭代访问
Enterprise电子表格通常包含多个命名工作表——例如,每月一个工作表、每个地区一个工作表或每个产品线一个工作表。IronXL 为您提供了多种访问这些工作表的方式:
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}");
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}");
Imports IronXL
Dim workbook As WorkBook = WorkBook.Load("annual_sales.xlsx")
' Option 1: access by name (throws if the sheet does not exist)
Dim januarySheet As WorkSheet = workbook.GetWorkSheet("January")
' Option 2: iterate all sheets in the workbook
For Each ws As WorkSheet In workbook.WorkSheets
Console.WriteLine($"Sheet: {ws.Name} | Rows: {ws.RowCount}")
' Read the header row from each sheet
Dim header As String = ws("A1").StringValue
Console.WriteLine($" Header: {header}")
Next
' Option 3: access by zero-based index
Dim lastSheet As WorkSheet = workbook.WorkSheets(workbook.WorkSheets.Count - 1)
Console.WriteLine($"Last sheet: {lastSheet.Name}")
在设计时已知工作表名时,GetWorkSheet是最清晰的选择。 对于动态处理——工作表名称来自用户输入或配置时,迭代WorkSheets集合可以避免硬编码假设,并能处理具有不同工作表数量的工作簿。
如何处理合并单元格和格式化区域?
报告和仪表盘经常使用合并单元格作为标题、分组标签和汇总行。 IronXL会读取合并区域左上角单元格的值,与 Excel 显示的值完全相同:
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}");
}
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}");
}
Imports IronXL
Dim workbook As WorkBook = WorkBook.Load("report_with_merges.xlsx")
Dim sheet As WorkSheet = workbook.DefaultWorkSheet
' The merged region A1:D1 stores its value in cell A1
Dim reportTitle As String = sheet("A1").StringValue
Console.WriteLine($"Report title : {reportTitle}")
' Read cell formatting metadata
Dim 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
For Each cell In sheet("A1:A100")
If Not cell.IsEmpty AndAlso cell.Style.Font.Bold Then
Console.WriteLine($"Section header at {cell.AddressString}: {cell.StringValue}")
End If
Next
Style属性树反映了OOXML SpreadsheetML规范的结构,所以如果您用过Open XML SDK,那么属性名称会显得很熟悉。 然而, IronXL将所有这些复杂性封装在一个简洁的 API 中,无需您进行任何 XML 操作。
如何使用同一个API导入CSV文件?
数据库导出、CRM系统和遗留应用程序生成的CSV文件可以通过相同的WorkBook.Load调用读取。 IronXL从文件内容中推断分隔符:
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}");
}
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}");
}
Imports IronXL
' Load a comma-separated values file -- same method, same API
Dim csvWorkbook As WorkBook = WorkBook.Load("export.csv")
Dim csvSheet As WorkSheet = csvWorkbook.DefaultWorkSheet
Console.WriteLine($"CSV rows loaded: {csvSheet.RowCount}")
' Process rows exactly like any other worksheet
For Each row In csvSheet.Rows
Dim id As String = row(0).StringValue
Dim name As String = row(1).StringValue
Console.WriteLine($"{id,-10} {name}")
Next
加载后,可以使用csvWorkbook.SaveAs("output.xlsx")将数据保存为XLSX。 这是 CSV 到 Excel 转换管道的常见模式——接收 CSV 文件,用计算列或格式丰富它,并将格式化的 XLSX 报告返回给用户。
对于制表符分隔的文件或自定义分隔符,使用WorkBook.LoadCSV("file.tsv", fileFormat: ExcelFileFormat.TSV)显式指定格式。
| 格式 | 扩展 | 出品方 | 注意事项 |
|---|---|---|---|
| XLSX | .xlsx |
Excel 2007+、LibreOffice | 默认现代格式;基于 XML |
| XLS | .xls |
Excel 97-2003 | 二进制格式;完全读/写支持 |
| ODS | .ods |
LibreOffice、OpenOffice | OpenDocument电子表格标准 |
| CSV | .csv |
任何申请 | 分隔符自动检测;无格式化 |
| TSV | .tsv |
数据库导出 | 制表符分隔;明确指定格式 |
IronXL与 Microsoft.Office.Interop.Excel 相比如何?
Interop、Open XML SDK 和IronXL并排使用
在.NET中, IronXL最常见的 Excel 自动化替代方案是Microsoft.Office.Interop.Excel 。 了解各种利弊有助于您为项目选择合适的工具。
Microsoft Interop 对 Excel COM 对象模型进行了封装。 这意味着必须在运行代码的每台机器上安装 Excel,包括 Web 服务器、构建代理和云虚拟机。 COM对象生命周期管理是手动的:您必须显式释放每一个 Range、Worksheet 和 Workbook 对象,否则Excel进程会在后台积累并占用内存,直到服务器重启。 许可也是一个需要考虑的问题:Office EULA 在许多情况下禁止服务器端自动化。
IronXL避免了所有这些限制。 这是一个纯粹的托管库,不依赖于 COM。 WorkBook对象是一个标准的.NET类; 垃圾回收器负责清理工作。你可以在开发人员的笔记本电脑、Azure 应用服务、Docker 容器或运行 Linux 的 Raspberry Pi 上运行相同的代码。
微软的Open XML SDK是另一种选择。它无需 Excel 即可直接访问 OOXML 文件格式,但它的操作层级非常低——您需要直接操作 XML 元素。 读取单个单元格值需要遍历共享字符串表、单元格引用和样式索引。 IronXL将所有这些都包装到本指南中展示的单行sheet["A1"].StringValue调用中。
如何在 Linux 和 Docker 上部署 Excel Processing?
在服务器部署中,IronXL 独立于 Excel 的优势体现得最为明显。 在 Windows 上编写的相同代码,在 Ubuntu、Alpine Linux 或 macOS 上无需修改即可运行。 对于容器化部署,您的 Dockerfile 不需要任何特殊配置:
# 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"]
# 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"]
对于Azure Functions和 AWS Lambda, IronXL可在托管运行时中运行,无需任何额外配置。 由于没有 COM 初始化步骤,冷启动开销极小。
线程安全是内置的:多个线程可以同时打开不同的WorkBook实例,无需协调。 如果您需要并行处理成千上万个文件,比如在后台工作中处理用户上传的电子表格,您可以在一组 WorkBook 实例上使用 Parallel.ForEach 或 Task.WhenAll,而不会有损坏的风险。
由于IronXL在初始化时只将请求的工作表加载到内存中,而不是将整个工作簿加载到内存中,因此内存使用情况保持可预测性。 对于非常大的文件,这种区别很重要:一个包含十个 50MB 工作表的簿子并不需要 500MB 的 RAM 来读取单个工作表。 IronXL性能文档涵盖了处理高容量文件处理场景的其他策略。
下一步计划是什么?
在项目中验证IronXL 的最快方法是安装NuGet包,然后针对环境中的真实文件运行本指南中的示例。 免费试用许可证可解锁所有功能,无需更改代码即可在准备投入生产时使用。
探索IronXL 的其他相关功能,这些功能可以补充文件读取功能:
- 在C#中编写和创建Excel文件——以编程方式生成报告和数据导出
- 格式化单元格、行和列——在代码中应用颜色、字体和边框
- 在C#中使用Excel公式——读取和写入公式单元格
- 将Excel转换为PDF在.NET中——从电子表格数据生成PDF报告
- IronXL API 文档——所有类和方法的完整参考
- IronXL 的许可和定价——面向个人开发者和Enterprise团队的选项
- IronXL NuGet页面-- 所有项目类型的安装说明
- IronXL教程——常见用例的逐步指南
- 将IronXL与EPPlus进行比较——并排的功能和许可比较
- IronXL产品主页——功能概述和入门资源
对于许可、跨平台支持或特定文件格式要求方面的问题, IronXL支持团队可通过在线聊天和电子邮件提供帮助。
常见问题解答
如何在未安装Excel的情况下,用C#读取OpenOffice Excel文件?
您可以使用IronXL库在 C# 中读取 OpenOffice Excel 文件,而无需在服务器上安装 Excel。它允许您使用单个 WorkBook.Load 方法调用高效地加载 XLS、XLSX、ODS 和 CSV 文件。
IronXL可以处理哪些类型的Excel文件?
IronXL支持处理各种 Excel 文件格式,包括 XLS、XLSX、ODS(OpenDocument Spreadsheet)和 CSV 文件,这使其能够灵活地用于不同的电子表格应用程序,包括 LibreOffice 和 OpenOffice。
为什么开发人员应该使用IronXL而不是 Microsoft Interop 来读取 Excel 文件?
IronXL提供了一种更简单、更高效的方式来处理 Excel 文件,无需 Microsoft Excel 或 COM Interop,从而降低了生产服务器的复杂性和开销,并支持 Linux 和 Docker 部署。
IronXL能否处理除 MS Excel 以外的电子表格应用程序创建的文件?
是的, IronXL可以读取和处理来自其他电子表格应用程序(如 OpenOffice Calc 和 LibreOffice Calc)的文件,使其成为使用 ODS 和 ODF 兼容格式的开发人员的灵活工具。
使用IronXL是否必须在生产服务器上安装 Excel?
不,使用IronXL无需在生产服务器上安装 Excel,这简化了部署并降低了维护需求。IronXLIronXL在 Windows、Linux、macOS 以及 Docker 容器中运行。
IronXL是否支持处理CSV文件?
是的, IronXL完全支持使用相同的 WorkBook.Load API 读取和处理 CSV 文件以及其他 Excel 格式(如 XLS、XLSX 和 ODS)。
对于.NET开发人员来说,使用IronXL有哪些好处?
IronXL为.NET开发人员提供了一个易于使用的库,用于读取、写入和操作 Excel 文件,而无需 Microsoft Excel,通过简洁、强类型的 API 提高生产力并缩短开发时间。
IronXL如何提高处理 Excel 文件的效率?
IronXL通过消除对 Excel 软件的需求来提高效率,提供类型化的单元格值访问器、线程安全的并发处理以及直接在.NET应用程序中处理 Excel 文件的轻量级解决方案。




