如何在未安装 Excel 的情况下使用 C# 读取 OpenOffice Excel 文件
使用正确的库,在 C# 中读取和处理 OpenDocument Spreadsheet (光学数据系统) 和 Excel 文件非常简单。 使用IronXL ,您可以通过一次方法调用将任何 XLS、XLSX、光学数据系统 或 CSV 文件加载到 WorkBook 对象中——无需安装 Microsoft Excel,无需 COM 注册,也无需 Interop 方面的烦恼。 本指南将引导您完成每个步骤:安装软件包、加载文件、提取键入的单元格值、使用命名工作表、处理合并单元格以及部署到 Linux 或容器化环境。
如何在.NET项目中安装IronXL ?
NuGet包管理器安装
通过NuGet包管理器将IronXL添加到您的项目中。 在 Visual Studio 中打开软件包管理器控制台并运行:
Install-Package IronXL
dotnet add package IronXL
Install-Package IronXL
dotnet add package IronXL
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 方法以相同的方式处理 光学数据系统、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 |
字符串
| 空字符串 | 始终安全;可将任何单元格转换为文本 |
IntValue |
int |
0 |
截断小数 |
DecimalValue |
decimal |
0m |
保持财务数据的精确性 |
DoubleValue |
double |
0.0 |
用于科学或统计值 |
BoolValue |
布尔
| false |
读取 Excel 中的 TRUE/FALSE 单元格 |
DateTimeValue |
DateTime? |
null |
可空——使用前请检查 |
如何处理多个已命名的工作表?
按名称、索引或迭代访问
Enterprise电子表格通常包含多个命名工作表——例如,每月一个工作表、每个地区一个IronXL表或每个产品线一个工作表。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", file翻译格式: ExcelFile翻译格式.TSV) 显式指定格式。
| 翻译格式 | 扩展 | 出品方 | 注意事项 |
|---|---|---|---|
| XLSX | .xlsx |
Excel 2007+、LibreOffice | 默认现代格式;基于 XML |
| XLS | .xls |
Excel 97-2003 | 二进制格式;完全读/写支持 |
| 光学数据系统 | .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 实例而无需协调。 如果您需要并行处理数千个文件(例如,在后台作业中处理用户上传的电子表格),则可以在 Parallel.ForEach 或 Task.WhenAll 实例池中使用 WorkBook 实例,而不会有损坏的风险。
由于IronXL在初始化时只将请求的工作表加载到内存中,而不是将整个工作簿加载到内存中,因此内存使用情况保持可预测性。 对于非常大的文件,这种区别很重要:一个包含十个 50MB 工作表的簿子并不需要 500MB 的 RAM 来读取单个工作表。 IronXL性能文档涵盖了处理大容量文件处理场景的其他策略。
下一步计划是什么?
在项目中验证IronXL 的最快方法是安装NuGet包,然后针对环境中的真实文件运行本指南中的示例。 免费试用许可证可解锁所有功能,无需更改代码即可在准备投入生产时使用。
探索IronXL 的其他相关功能,这些功能可以补充文件读取功能:
使用 C# 编写和创建 Excel 文件——以编程方式构建报表和数据导出 -设置单元格、行和列的格式——通过代码应用颜色、字体和边框。 -使用 C# 处理 Excel 公式——读取和写入公式单元格 -在.NET中将 Excel 转换为 PDF -- 从电子表格数据生成 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 文件的轻量级解决方案。


