Linq To Excel
Linq to Excel為一Open Source函式庫,該函式庫能讓我們使用Linq去對Excel與CSV做查詢的動作。
使用前需先將LinqToExcel.dll與Remotion.Data.Linq.dll這兩個組件檔給加入參考,並加入LinqToExcel命名空間就可以開始使用Linq to Excel了。
開始使用前需了解到ExcelQueryFactory為Linq to Excel的主要類別,我們主要都是對該類別下去做操作,因此我們必需要了解其內部的成員,這邊將其成員整理列表如下:
屬性
Name | Description |
FileName | 檔案名稱 |
StrictMapping | 是否限制AddMapping所有設定的對應都要正確 |
方法
Name | Description |
Worksheet | 取得工作表中的資料 |
WorksheetNoHeader | 取得工作表中不含標題的資料 |
WorksheetRange | 取得工作表中特定範圍的資料 |
WorksheetRangeNoHeader | 取得工作表中不含標題的特定範圍資料 |
AddMapping | 設定Excel欄位與物件屬性的對應 |
AddTransformation | 設定Excel欄位塞給物件屬性所要做的轉換動作 |
GetWorksheetNames | 取得所有工作表名稱 |
GetColumnNames | 取得所有欄位名稱 |
建立ExcelQueryFactory物件時我們有兩種選擇,一種是直接將Excel檔案位置帶入建構子建構。
var excel = new ExcelQueryFactory("Data.xls");
一種是使用預設建構子建立後,再透過FileName屬性設定Excel檔案位置。
var excel = new ExcelQueryFactory();
excel.FileName = "Data.xls";
建立ExcelQueryFactory物件後,可以使用GetWorksheetNames方法可以取得所有工作表名稱 。
void ShowWorkSheetNames(string excelFile)
{
var excel = new ExcelQueryFactory(excelFile);
var workSheetNames = excel.GetWorksheetNames();
foreach (var item in workSheetNames)
{
System.Console.WriteLine(item.ToString());
}
}
GetColumnNames方法可取得指定工作表中所有欄位的名稱。
void ShowColumnNames(string excelFile,string sheetName)
{
var excel = new ExcelQueryFactory(excelFile);
var columnNames = excel.GetColumnNames(sheetName);
foreach (var item in columnNames)
{
System.Console.WriteLine(item.ToString());
}
}
這邊個人是發現在不同版本的Excel下,這道方法會取得的值會不有所不同,取得的值在某些條件下都會怪怪的,要特別留意一下。像是我在2003的Excel打入下列資料:
使用GetColumnNames方法取得的值會像下面這樣,只要Column打的是數值,取出來都會走樣。
同樣的資料在Excel 2007下,跑起來就正常許多,但在空行的部份仍是跟我預期的不同。
Worksheet、WorksheetNoHeader、WorksheetRange、WorksheetRangeNoHeader等方法可取得工作表內的資料,我們可藉這些方法取得回傳值後對這些工作表內的資料做Linq查詢。
...
var excel = new ExcelQueryFactory(excelFile);
//自己可自行加要過濾的條件,這邊只是示範
var linq = from item in excel.Worksheet(sheetName)
select item;
...
這些WorkSheet開頭方法多半會具有不含參數的多載版本,可用以取得"Sheet1"工作表內的資料,這邊需注意該方法取得的是"Sheet1"工作表內的資料,而非第一個工作表內的資料,工作表改名後使用該多載版本方法就會取不到。
...
var excel = new ExcelQueryFactory(excelFile);
//這邊會取使用Sheet1的工作表內容去做查詢動作
var linq = from item in excel.Worksheet()
select item;
...
或是具有帶入工作表索引或工作表名稱的多載版本,用以取得指定索引或名稱的工作表內的資料。有的還會含有泛型的多載版本,可帶入資料對應的物件類型,取得Excel資料時Linq To Excel會自動幫我們將資料塞成指定的類別。
...
var excel = new ExcelQueryFactory(excelFile);
var linq = from item in excel.Worksheet<Blogger>(sheetName)
where item.Sex==SexType.Boy
select item;
...
在使用泛型多載版本時,要是用以填值的類別其屬性跟Excel欄位名稱不符,我們可以透過AddMapping設定兩者間的對應關係。
...
var excel = new ExcelQueryFactory(excelFile);
excel.AddMapping<Blogger>(item => item.FirstName, "First Name");
excel.AddMapping<Blogger>(item => item.LastName, "Last Name");
...
若是設定完欄位與屬性的對應後,有些屬性的資料與欄位內的資料或是型態有所差異時,可加設AddTransformation去做兩者間的轉換。
...
var excel = new ExcelQueryFactory(excelFile);
excel.AddMapping<Blogger>(item => item.FirstName, "First Name");
excel.AddMapping<Blogger>(item => item.LastName, "Last Name");
excel.AddTransformation<Blogger>(item => item.Sex, item => (item == "Boy") ? SexType.Boy : SexType.Girl);
...
另外一提,Linq to Excel在使用上會自動去找尋第一個符合的資料,就算內容不是從Excel最左上的A1欄位開始,Linq to Excel都會幫我們自動找尋,多半我們可以不指定要抓取的範圍,除非工作表內的資料是分成好幾塊。
完整範例
若有需要範例程式可至larrynung / LinqToExcelDemo這邊下載。
Data.xls
SexType.cs
namespace ConsoleApplication1
{
enum SexType
{
Boy,
Girl
}
}
Blogger.cs
using System;
namespace ConsoleApplication1
{
class Blogger
{
public int ID { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public SexType Sex { get; set; }
public int Age { get; set; }
public String Blog { get; set; }
public override string ToString()
{
return string.Join(",", new string[] { ID.ToString(), FirstName, LastName, Sex.ToString(), Age.ToString(), Blog });
}
}
}
Program.cs
using LinqToExcel;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
const string EXCEL_FILE = "Data.xls";
const string FIRST_SHEET = "BlogData1";
const string SECOND_SHEET = "BlogData2";
var excel = new ExcelQueryFactory(EXCEL_FILE);
System.Console.WriteLine("Excel File: {0}", excel.FileName);
System.Console.WriteLine();
System.Console.WriteLine("WorksheetNames...");
var workSheetNames = excel.GetWorksheetNames();
foreach (var item in workSheetNames)
{
System.Console.WriteLine(item.ToString());
}
System.Console.WriteLine();
System.Console.WriteLine("BlogData's Columns...");
var columnNames = excel.GetColumnNames(FIRST_SHEET);
foreach (var item in columnNames)
{
System.Console.WriteLine(item.ToString());
}
System.Console.WriteLine();
System.Console.WriteLine("BlogData1 With ExcelQueryFactory.Worksheet...");
excel.AddMapping<Blogger>(item => item.FirstName, "First Name");
excel.AddMapping<Blogger>(item => item.LastName, "Last Name");
excel.AddTransformation<Blogger>(item => item.Sex, item => (item == "Boy") ? SexType.Boy : SexType.Girl);
foreach (var item in excel.Worksheet<Blogger>(FIRST_SHEET))
{
System.Console.WriteLine(item.ToString());
}
System.Console.WriteLine();
System.Console.WriteLine("BlogData2 With ExcelQueryFactory.Worksheet...");
foreach (var item in excel.Worksheet<Blogger>(SECOND_SHEET))
{
System.Console.WriteLine(item.ToString());
}
System.Console.WriteLine();
System.Console.WriteLine("BlogData2 With ExcelQueryFactory.WorksheetRange...");
foreach (var item in excel.WorksheetRange<Blogger>("B2", "G3", SECOND_SHEET))
{
System.Console.WriteLine(item.ToString());
}
}
}
}
運行後結果如下: