如何在 C# 中讀取 Excel 檔案而不是使用 StreamReader
許多 C# 開發人員在處理 Excel 檔案時會遇到一個令人沮喪的挑戰:能夠可靠地處理文字檔案的 StreamReader 類,在指向 Excel 文件時會完全失效。 如果您嘗試使用 C# 中的 StreamReader 讀取 Excel 文件,卻只看到亂碼、二進位雜訊或意外異常,那麼您並不孤單。 本指南詳細解釋了為什麼 StreamReader 無法處理 Excel 文件,並向您展示如何使用IronXL (一個專用於 .NET 的 Excel 庫,無需安裝 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.org 上,名為 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,這是一個功能強大的庫,它允許您在 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 資料整合到其他應用程式中。


