如何在 C# 中读取 Excel 文件而不是使用 StreamReader
许多 C# 开发人员在处理 Excel 文件时会遇到一个令人沮丧的挑战:能够可靠地处理文本文件的 StreamReader 类,在指向 Excel 文档时会完全失效。 如果您尝试使用 C# 中的 StreamReader 读取 Excel 文件,却只看到乱码、二进制噪声或意外异常,那么您并不孤单。 本指南详细解释了为什么 StreamReader 无法处理 Excel 文件,并向您展示如何使用IronXL (一个无需安装 Excel 的 .NET 专用 Excel 库)正确解决此问题。
这种混淆通常是因为 CSV 文件(Excel 可以打开和保存)与 StreamReader 兼容良好。 真正的 Excel 文件(XLSX、XLS、XLSM)需要采用完全不同的方法。 理解这一区别将为您节省数小时的调试时间,并引导您找到完成这项工作的正确工具。
! C# 中使用 StreamReader 读取 Excel 文件的替代方案 - IronXL:图 1 - IronXL
为什么 StreamReader 无法读取 Excel 文件?
StreamReader 是一个基于文本的阅读器。 它使用指定的编码(UTF-8、ASCII 等)逐行读取字符数据,并且不了解二进制结构或压缩存档。 官方的.NET StreamReader 文档证实,此类专为字符编码文本而设计。 Excel 文件虽然看起来像简单的电子表格,但实际上是复杂的二进制或 ZIP 压缩的 XML 结构,StreamReader 无法解释。
当您使用 StreamReader 打开 XLSX 文件时,您实际上是在尝试将 ZIP 压缩文件作为纯文本读取。 结果得到的不是电子表格数据,而是一串二进制噪声。
// This code will NOT work -- demonstrates the problem
using StreamReader reader = new StreamReader("ProductData.xlsx");
string content = reader.ReadLine();
Console.WriteLine(content); // Outputs garbled binary data like "PK♥♦"
// This code will NOT work -- demonstrates the problem
using StreamReader reader = new StreamReader("ProductData.xlsx");
string content = reader.ReadLine();
Console.WriteLine(content); // Outputs garbled binary data like "PK♥♦"
Imports System.IO
' This code will NOT work -- demonstrates the problem
Using reader As New StreamReader("ProductData.xlsx")
Dim content As String = reader.ReadLine()
Console.WriteLine(content) ' Outputs garbled binary data like "PK♥♦"
End Using
运行此代码片段后,您看到的不是电子表格行,而是诸如 PK♥♦ 之类的二进制字符或类似乱码。这是因为:
- XLSX 文件是包含多个 XML 文件的 ZIP 压缩包:工作表、样式、共享字符串、关系。 Open XML SDK 文档提供了该结构的详细说明。
- XLS 文件使用专有的二进制格式(BIFF——二进制交换文件格式)
StreamReader会对读取的所有字节应用字符编码,导致两种格式的输出都毫无意义。
示例输入
! C# 中使用 StreamReader 读取 Excel 文件的替代方案 - IronXL:图 2 - Excel 输入
使用 StreamReader 时输出乱码
! 使用 C# 中的 StreamReader 读取 Excel 文件的替代方案 - IronXL:图 3 - 控制台输出
为什么 CSV 格式可以运行而 XLSX 格式不行
CSV(逗号分隔值)是一种纯文本格式。 每一行代表一行文本,每一列之间用逗号分隔。 StreamReader 读取 CSV 文件没有问题,因为它们不包含二进制数据或压缩存档。 XLSX 从根本上来说有所不同:它将多个 XML 文档打包到一个 ZIP 容器中,其中包含元数据、主题和样式定义。 不可能逐行阅读。
在选择工具时,这种区别很重要。 对于 CSV 文件,StreamReader 或 File.ReadAllLines 完全足够。 对于真正的 Excel 工作簿,你需要一个能够从结构层面理解其格式的库。
如何在.NET项目中安装IronXL ?
IronXL是一个.NET库,无需安装 Microsoft Excel 即可读取、写入和创建 Excel 文件。 它支持 XLSX、XLS、XLSM、CSV 和 TSV 格式,并且可以在 Windows、Linux、macOS 和 Docker 容器上运行。
要安装IronXL,可以使用NuGet包管理器控制台或.NET CLI。 该软件包已发布在NuGet上,名称为IronXL :
Install-Package IronXL
dotnet add package IronXL
Install-Package IronXL
dotnet add package IronXL
安装完成后,将 using IronXL; 指令添加到您的文件中,即可开始处理 Excel 文档。
! 使用 C# 中的 StreamReader 读取 Excel 文件的替代方案 - IronXL:图 5 - 安装
有关详细的安装步骤和NuGet配置选项,请参阅IronXL NuGet安装指南。 我们提供免费试用许可证,您可以在购买前在您的项目中评估IronXL 的效果。
如何使用IronXL读取 Excel 文件?
IronXL提供了一个直观的 API,用于在 C# 中读取 Excel 文件。 与 StreamReader 不同,IronXL 了解 Excel 的内部结构,并为您提供对行、列和单元格值的清晰访问。 IronXL文档提供了所有受支持操作的完整 API 参考。
以下是如何使用IronXL和顶级语句读取 Excel 文件:
using IronXL;
// Load the Excel file from disk
WorkBook workbook = WorkBook.Load("ProductData.xlsx");
WorkSheet worksheet = workbook.DefaultWorkSheet;
// Read a specific cell by address
string cellValue = worksheet["A1"].StringValue;
Console.WriteLine($"Cell A1 contains: {cellValue}");
// Iterate over a range of cells
foreach (var cell in worksheet["A1:C10"])
{
Console.WriteLine($"{cell.AddressString}: {cell.Text}");
}
// Read a numeric value
decimal price = worksheet["B2"].DecimalValue;
Console.WriteLine($"Price: {price:C}");
using IronXL;
// Load the Excel file from disk
WorkBook workbook = WorkBook.Load("ProductData.xlsx");
WorkSheet worksheet = workbook.DefaultWorkSheet;
// Read a specific cell by address
string cellValue = worksheet["A1"].StringValue;
Console.WriteLine($"Cell A1 contains: {cellValue}");
// Iterate over a range of cells
foreach (var cell in worksheet["A1:C10"])
{
Console.WriteLine($"{cell.AddressString}: {cell.Text}");
}
// Read a numeric value
decimal price = worksheet["B2"].DecimalValue;
Console.WriteLine($"Price: {price:C}");
Imports IronXL
' Load the Excel file from disk
Dim workbook As WorkBook = WorkBook.Load("ProductData.xlsx")
Dim worksheet As WorkSheet = workbook.DefaultWorkSheet
' Read a specific cell by address
Dim cellValue As String = worksheet("A1").StringValue
Console.WriteLine($"Cell A1 contains: {cellValue}")
' Iterate over a range of cells
For Each cell In worksheet("A1:C10")
Console.WriteLine($"{cell.AddressString}: {cell.Text}")
Next
' Read a numeric value
Dim price As Decimal = worksheet("B2").DecimalValue
Console.WriteLine($"Price: {price:C}")
WorkBook.Load 方法会自动检测文件格式(XLSX、XLS、XLSM、CSV),并处理所有复杂的解析。 您可以使用标准的 Excel 表示法(例如 "A1")或范围(例如 "A1:C10")来访问单元格,这使得任何熟悉电子表格的人都能立即阅读代码。
访问多个工作表
许多练习册包含不止一张工作表。 IronXL允许您打开和浏览工作簿,并完整列出所有工作表:
using IronXL;
WorkBook workbook = WorkBook.Load("MultiSheet.xlsx");
// List all worksheets
foreach (WorkSheet sheet in workbook.WorkSheets)
{
Console.WriteLine($"Sheet: {sheet.Name}, Rows: {sheet.RowCount}");
}
// Access a sheet by name
WorkSheet summary = workbook.GetWorkSheet("Summary");
string totalRevenue = summary["B20"].StringValue;
Console.WriteLine($"Total Revenue: {totalRevenue}");
// Access a sheet by index
WorkSheet firstSheet = workbook.WorkSheets[0];
int lastRow = firstSheet.RowCount;
Console.WriteLine($"Last row in first sheet: {lastRow}");
using IronXL;
WorkBook workbook = WorkBook.Load("MultiSheet.xlsx");
// List all worksheets
foreach (WorkSheet sheet in workbook.WorkSheets)
{
Console.WriteLine($"Sheet: {sheet.Name}, Rows: {sheet.RowCount}");
}
// Access a sheet by name
WorkSheet summary = workbook.GetWorkSheet("Summary");
string totalRevenue = summary["B20"].StringValue;
Console.WriteLine($"Total Revenue: {totalRevenue}");
// Access a sheet by index
WorkSheet firstSheet = workbook.WorkSheets[0];
int lastRow = firstSheet.RowCount;
Console.WriteLine($"Last row in first sheet: {lastRow}");
Imports IronXL
Dim workbook As WorkBook = WorkBook.Load("MultiSheet.xlsx")
' List all worksheets
For Each sheet As WorkSheet In workbook.WorkSheets
Console.WriteLine($"Sheet: {sheet.Name}, Rows: {sheet.RowCount}")
Next
' Access a sheet by name
Dim summary As WorkSheet = workbook.GetWorkSheet("Summary")
Dim totalRevenue As String = summary("B20").StringValue
Console.WriteLine($"Total Revenue: {totalRevenue}")
' Access a sheet by index
Dim firstSheet As WorkSheet = workbook.WorkSheets(0)
Dim lastRow As Integer = firstSheet.RowCount
Console.WriteLine($"Last row in first sheet: {lastRow}")
这种方法比任何尝试使用 StreamReader 解析 Excel 或进行字符串操作都要干净得多。
如何从内存流中读取Excel数据?
实际应用中经常需要处理来自数据流而不是磁盘文件的 Excel 文件。 常见场景包括处理从 Web 表单上传的文件、从数据库 BLOB 列检索工作簿,或处理从云存储(Azure Blob Storage、AWS S3)下载的文件。 IronXL 通过 WorkBook.FromStream 处理这些情况:
using IronXL;
using System.IO;
// Simulate reading file bytes (e.g., from a database or web upload)
byte[] fileBytes = File.ReadAllBytes("ProductData.xlsx");
using MemoryStream stream = new MemoryStream(fileBytes);
WorkBook workbook = WorkBook.FromStream(stream);
WorkSheet worksheet = workbook.DefaultWorkSheet;
// Get row and column counts
Console.WriteLine($"Rows: {worksheet.RowCount}, Columns: {worksheet.ColumnCount}");
// Convert to DataTable for database or grid binding
var dataTable = worksheet.ToDataTable(useHeaderRow: true);
Console.WriteLine($"Loaded {dataTable.Rows.Count} data rows");
foreach (System.Data.DataRow row in dataTable.Rows)
{
string productName = row["ProductName"]?.ToString() ?? string.Empty;
string sku = row["SKU"]?.ToString() ?? string.Empty;
Console.WriteLine($"Product: {productName}, SKU: {sku}");
}
using IronXL;
using System.IO;
// Simulate reading file bytes (e.g., from a database or web upload)
byte[] fileBytes = File.ReadAllBytes("ProductData.xlsx");
using MemoryStream stream = new MemoryStream(fileBytes);
WorkBook workbook = WorkBook.FromStream(stream);
WorkSheet worksheet = workbook.DefaultWorkSheet;
// Get row and column counts
Console.WriteLine($"Rows: {worksheet.RowCount}, Columns: {worksheet.ColumnCount}");
// Convert to DataTable for database or grid binding
var dataTable = worksheet.ToDataTable(useHeaderRow: true);
Console.WriteLine($"Loaded {dataTable.Rows.Count} data rows");
foreach (System.Data.DataRow row in dataTable.Rows)
{
string productName = row["ProductName"]?.ToString() ?? string.Empty;
string sku = row["SKU"]?.ToString() ?? string.Empty;
Console.WriteLine($"Product: {productName}, SKU: {sku}");
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
WorkBook.FromStream 接受任何 Stream -- MemoryStream、FileStream 或网络流。 这种灵活性意味着您无需为了读取 Excel 数据而将临时文件写入磁盘。 转换为 DataTable 还可以直接与 SqlBulkCopy、数据绑定控件和报表框架集成。
流处理的输出
! C# 中使用 StreamReader 读取 Excel 文件的替代方案 - IronXL:图 6 - 从 MemoryStream 输出读取 Excel 文件
何时使用事件驱动型 Excel 读取?
在事件驱动架构中(例如,Windows Forms 中的文件上传按钮或 ASP.NET 控制器操作),方法签名通常包含 object sender 和 EventArgs e 参数。 Excel 处理逻辑仍然使用相同的IronXL API,但它是从事件处理程序内部调用的,而不是从顶级语句调用的。 IronXL可以无缝集成到任何事件驱动或异步工作流程中,因为它不依赖于 UI 线程。
如何在Excel和CSV格式之间进行转换?
虽然 StreamReader 可以处理 CSV 文件,但生产应用经常需要在 Excel 和 CSV 之间传输数据。IronXL 使格式转换变得简单易行。 只需几行代码,即可将 Excel 数据导出为 CSV 文件,或将 CSV 数据导入到工作簿中:
using IronXL;
// Load an Excel file and save as CSV
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
workbook.SaveAsCsv("output.csv");
// Load a CSV file and save as Excel
WorkBook csvWorkbook = WorkBook.LoadCSV("legacy-report.csv");
csvWorkbook.SaveAs("converted.xlsx");
// Export a specific worksheet to CSV
WorkSheet worksheet = workbook.WorkSheets[0];
worksheet.SaveAsCsv("sheet1-export.csv");
using IronXL;
// Load an Excel file and save as CSV
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
workbook.SaveAsCsv("output.csv");
// Load a CSV file and save as Excel
WorkBook csvWorkbook = WorkBook.LoadCSV("legacy-report.csv");
csvWorkbook.SaveAs("converted.xlsx");
// Export a specific worksheet to CSV
WorkSheet worksheet = workbook.WorkSheets[0];
worksheet.SaveAsCsv("sheet1-export.csv");
IRON VB CONVERTER ERROR developers@ironsoftware.com
这些转换操作会在更改容器格式的同时保留您的数据。 将 Excel 转换为 CSV 时, IronXL默认导出第一个工作表; 您可以指定任何您选择的图纸。 将 CSV 文件转换为 Excel 文件会创建一个结构正确的 Excel 工作簿,您可以对其进行格式化、添加公式并写入其他数据。
格式支持方面有哪些区别?
| 文件格式 | StreamReader | IronXL | 注意事项 |
|---|---|---|---|
| CSV(.csv) | 是 | 是 | 纯文本;StreamReader 工作正常 |
| XLSX (.xlsx) | 无 | 是 | ZIP压缩的XML;需要库 |
| XLS(.xls) | 无 | 是 | 二进制 BIFF 格式;需要库 |
| XLSM (.xlsm) | 无 | 是 | 启用宏的工作簿 |
| TSV(.tsv) | 是 | 是 | 制表符分隔的纯文本 |
如何使用IronXL创建和格式化 Excel 文件?
读取Excel数据只是工作流程的一部分。 许多应用程序还需要创建新的 Excel 文件并应用格式。 IronXL支持单元格格式设置,包括字体、颜色、边框、数字格式和单元格合并:
using IronXL;
// Create a new workbook and worksheet
WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workbook.CreateWorkSheet("Report");
// Write headers with formatting
sheet["A1"].Value = "Product";
sheet["B1"].Value = "Units Sold";
sheet["C1"].Value = "Revenue";
// Apply bold formatting to header row
sheet["A1:C1"].Style.Font.Bold = true;
sheet["A1:C1"].Style.SetBackgroundColor("#4472C4");
sheet["A1:C1"].Style.Font.Color = "#FFFFFF";
// Write data rows
string[] products = { "Widget A", "Widget B", "Widget C" };
int[] units = { 120, 85, 210 };
decimal[] revenues = { 2400.00m, 1700.00m, 4200.00m };
for (int i = 0; i < products.Length; i++)
{
sheet[$"A{i + 2}"].Value = products[i];
sheet[$"B{i + 2}"].Value = units[i];
sheet[$"C{i + 2}"].Value = revenues[i];
sheet[$"C{i + 2}"].FormatString = "$#,##0.00";
}
// Save the workbook
workbook.SaveAs("FormattedReport.xlsx");
Console.WriteLine("Report created successfully.");
using IronXL;
// Create a new workbook and worksheet
WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workbook.CreateWorkSheet("Report");
// Write headers with formatting
sheet["A1"].Value = "Product";
sheet["B1"].Value = "Units Sold";
sheet["C1"].Value = "Revenue";
// Apply bold formatting to header row
sheet["A1:C1"].Style.Font.Bold = true;
sheet["A1:C1"].Style.SetBackgroundColor("#4472C4");
sheet["A1:C1"].Style.Font.Color = "#FFFFFF";
// Write data rows
string[] products = { "Widget A", "Widget B", "Widget C" };
int[] units = { 120, 85, 210 };
decimal[] revenues = { 2400.00m, 1700.00m, 4200.00m };
for (int i = 0; i < products.Length; i++)
{
sheet[$"A{i + 2}"].Value = products[i];
sheet[$"B{i + 2}"].Value = units[i];
sheet[$"C{i + 2}"].Value = revenues[i];
sheet[$"C{i + 2}"].FormatString = "$#,##0.00";
}
// Save the workbook
workbook.SaveAs("FormattedReport.xlsx");
Console.WriteLine("Report created successfully.");
Imports IronXL
' Create a new workbook and worksheet
Dim workbook As WorkBook = WorkBook.Create(ExcelFileFormat.XLSX)
Dim sheet As WorkSheet = workbook.CreateWorkSheet("Report")
' Write headers with formatting
sheet("A1").Value = "Product"
sheet("B1").Value = "Units Sold"
sheet("C1").Value = "Revenue"
' Apply bold formatting to header row
sheet("A1:C1").Style.Font.Bold = True
sheet("A1:C1").Style.SetBackgroundColor("#4472C4")
sheet("A1:C1").Style.Font.Color = "#FFFFFF"
' Write data rows
Dim products As String() = {"Widget A", "Widget B", "Widget C"}
Dim units As Integer() = {120, 85, 210}
Dim revenues As Decimal() = {2400.0D, 1700.0D, 4200.0D}
For i As Integer = 0 To products.Length - 1
sheet($"A{i + 2}").Value = products(i)
sheet($"B{i + 2}").Value = units(i)
sheet($"C{i + 2}").Value = revenues(i)
sheet($"C{i + 2}").FormatString = "$#,##0.00"
Next
' Save the workbook
workbook.SaveAs("FormattedReport.xlsx")
Console.WriteLine("Report created successfully.")
IronXL既能读取现有工作簿,又能创建新的格式化文件,使其成为适用于.NET应用程序的完整 Excel 解决方案。 请查看IronXL 的完整功能页面,了解支持的操作的详细信息。
将数据导出为其他格式
IronXL还支持将工作簿数据导出到DataSet 对象,这在将多个工作表加载到内存中进行跨工作表计算或数据库批量插入操作时特别有用。 ToDataSet 方法返回一个 DataSet,其中每个工作表都变成一个 DataTable。
如何在生产环境中获得IronXL 的许可并进行部署?
IronXL 可免费用于开发和测试。 生产应用需要许可证。 您可以访问产品页面了解IronXL 的许可选项,根据您的部署需求,这些选项涵盖开发人员、团队和组织级别。
购买后,请在调用任何IronXL函数之前,在代码中应用您的许可证密钥:
IronXL.License.LicenseKey = "YOUR-LICENSE-KEY-HERE";
IronXL.License.LicenseKey = "YOUR-LICENSE-KEY-HERE";
Imports IronXL
IronXL.License.LicenseKey = "YOUR-LICENSE-KEY-HERE"
或者,在部署环境中设置 IRONXL_LICENSE_KEY 环境变量,IronXL 将自动识别它。 对于容器化部署(Docker、Kubernetes)和云环境,这是首选方法,因为在这些环境中,硬编码密钥是不可接受的。
为了便于评估,免费试用许可证提供完整功能,以便您在购买前验证IronXL是否适用于您的特定工作负载。 无需信用卡即可试用,试用期立即生效。
与 Microsoft.Office.Interop.Excel 等替代方案相比, IronXL具有以下几个部署优势:
- 服务器上无需安装 Microsoft Excel
- 兼容 Linux 和 Docker——这对云原生应用至关重要
- 没有 COM 对象生命周期管理或单元线程问题
- 服务器环境下启动速度更快,内存占用更低
- 在所有支持的平台上表现一致
IronXL具备这些特性,对于任何需要在生产环境中处理 Excel 文件的.NET应用程序来说,无论是在本地还是在云端,它都是一个实用的选择。
常见问题解答
为什么 StreamReader 不能直接处理 Excel 文件?
StreamReader 专为读取文本文件而设计,无法解析 Excel 文件中使用的二进制或复杂结构化数据格式。因此,尝试使用 StreamReader 直接读取 Excel 文件时,可能会出现乱码或异常。
在 C# 中读取 Excel 文件,推荐的解决方案是什么?
推荐的解决方案是使用IronXL,IronXL是一个功能强大的库,它允许您在 C# 中读取、编辑和创建 Excel 文件,而无需 Excel Interop。IronXL 可以高效地处理 Excel 文件的复杂结构。
IronXL相较于 Excel Interop 有哪些优势?
IronXL相比 Excel Interop 具有多项优势,包括更好的性能、无需在服务器或客户端计算机上安装 Excel、更容易部署,以及能够在 Web 和云环境中处理 Excel 文件。
IronXL是否能够处理 .xls 和 .xlsx 文件格式?
是的, IronXL能够处理 .xls 和 .xlsx Excel 文件格式,为处理不同类型 Excel 文档的开发人员提供了灵活性。
IronXL可以用于Web应用程序吗?
是的, IronXL 的设计用途广泛,可用于各种应用程序类型,包括 Web 应用程序,这得益于其轻量级特性以及与.NET Core和.NET Framework 的兼容性。
IronXL是否需要安装 Microsoft Excel?
不, IronXL不需要在服务器或客户端计算机上安装 Microsoft Excel,因此非常适合服务器端应用程序和云环境。
IronXL有哪些典型应用场景?
IronXL的典型用例包括从 Excel 文件中提取和分析数据、生成报告、自动创建和修改 Excel 文件以及将 Excel 数据集成到其他应用程序中。


