C#操作Excel的類以及其使用舉例說明

 1前言
這兩天由於某種需要,研究了一下.NET中對Excel的互操作,之前主要是直接通過第三方的組件等方式來操作的Excel,這次仔細的研究了一下,對常用的Excel操作需求做了一個簡單的總結,比如創建Excel,設置單元格樣式,合併單元格,導入內存中的DataTable,插入圖片、圖表等。在此基礎上藉助於Microsoft.Office.Interop.Excel對這些操作進行了封裝最終形成了ExcelHandler類。本文主要對自己封裝的這個類進行簡單的舉例說明,關於此類的完整代碼參見第三部分。
注意:對於命名空間Microsoft.Office.Interop.Excel,使用之前需要引用COM:Microsoft Office 11.0 Object Library(office 2003 )或者Microsoft Office 12.0 Object Library(office 2007 ),如果引用列表中沒有,需要自行添加 X:Program Files/Microsoft Office/OFFICE[11|12]/EXCEL.EXE的引用。如果已經安裝VSTO(Visual Studio Tools For Office),亦可直接添加對X:\Program Files\Microsoft Visual Studio [9.0|8.0]\Visual Studio Tools for Office\PIA\Office[11|12]\Microsoft.Office.Interop.Excel.dll的引用。

2ExcelHandler類舉例說明
爲了展示該類的使用方法,新建了一個WinForm的測試項目進行測試,項目名稱可自定,添加對ExcelHandler的dll的引用。所有測試代碼均放在窗體的一個按鈕單擊事件的處理方法中。

2.1創建Excel文件

 /// <summary>
/// 測試ExcelHandler類
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonTest_Click(object sender, EventArgs e)
{
string excelFilePath = string.Format("{0}Excel-{1}.xls", AppDomain.CurrentDomain.BaseDirectory, DateTime.Now.ToString("yyyyMMddHHmmss"));

using (ExcelHandler handler = new ExcelHandler(excelFilePath, true))
{
handler.OpenOrCreate();
MessageBox.Show("創建Excel成功!");
handler.Save();
MessageBox.Show(string.Format("保存Excel成功!Excel路徑:{0}", excelFilePath));

}

點擊按鈕執行後,可以看到在Debug目錄下多了一個Excel文件

此文件的完整路徑爲:F:\My Projects\Tanging.DataVisualization\Tanging.DataVisualization\bin\Debug\Excel-20100314181502.xls。
注意:之後的例子的Excel的文件的路徑需要爲你自己創建的Excel的相應路徑。
下面將舉例說明對此Excel文件進行操作。

2.2創建自己的工作表Worksheet
 private void buttonTest_Click(object sender, EventArgs e)
{
string excelFilePath = string.Format("{0}Excel-20100314181502.xls", AppDomain.CurrentDomain.BaseDirectory);

using (ExcelHandler handler = new ExcelHandler(excelFilePath, false))//設置第二個參數爲false表示直接打開現有的Excel文檔
{
handler.OpenOrCreate();
//創建一個Worksheet
Worksheet sheet = handler.AddWorksheet("TestSheet");
//刪除除TestSheet之外的其餘Worksheet
handler.DeleteWorksheetExcept(sheet);
handler.Save();
}
}
再次打開創建的Excel,可以看到新建的Worksheet

2.3單元格、Range等的操作

下面設置A1到E5的單元格樣式,並且設置單元格值等
private void buttonTest_Click(object sender, EventArgs e)
{
string excelFilePath = string.Format("{0}Excel-20100314181502.xls", AppDomain.CurrentDomain.BaseDirectory);

using (ExcelHandler handler = new ExcelHandler(excelFilePath, false))//設置第二個參數爲false表示直接打開現有的Excel文檔
{
handler.OpenOrCreate();
//獲得Worksheet對象
Worksheet sheet = handler.GetWorksheet("TestSheet");
//A1-E5
Range range = handler.GetRange(sheet, 1, 1, 5, 5);
handler.SetRangeFormat(range);

handler.SetCellValue(sheet, 1, 1, "測試");
handler.SetCellValue(sheet, 2, 1, "測試2");

range.Font.Bold = true;//加粗

handler.Save();
}
}
效果如下:

2.4導入DataTable
代碼如下:
private void buttonTest_Click(object sender, EventArgs e)
{
string excelFilePath = string.Format("{0}Excel-20100314181502.xls", AppDomain.CurrentDomain.BaseDirectory);

using (ExcelHandler handler = new ExcelHandler(excelFilePath, false))//設置第二個參數爲false表示直接打開現有的Excel文檔
{
handler.OpenOrCreate();
//獲得Worksheet對象
Worksheet sheet = handler.GetWorksheet("TestSheet");
//A1-E5
Range range = handler.GetRange(sheet, 1, 1, 5, 5);
handler.SetRangeFormat(range);
range.Font.Bold = true;

System.Data.DataTable table = new System.Data.DataTable();
table.Columns.AddRange(new DataColumn[] { new DataColumn("測試列1"), new DataColumn("測試列2"), new DataColumn("測試列3") });
Random random = new Random(20);
for (int i = 0; i < 10; i++)
{
table.Rows.Add(random.Next(10000), random.Next(10000), random.Next(10000));
}

//從第6行第一列導入數據
handler.ImportDataTable(sheet, "測試導入表格", true, new string[] { "測試列1", "測試列2", "測試列3" }, 6, 1, table);

handler.Save();
}
}

結果如下圖:

2.5 插入圖片
下面插入一張圖片到Excel的第一行第五列,代碼如下:
private void buttonTest_Click(object sender, EventArgs e)
{
string excelFilePath = string.Format("{0}Excel-20100314181502.xls", AppDomain.CurrentDomain.BaseDirectory);

using (ExcelHandler handler = new ExcelHandler(excelFilePath, false))//設置第二個參數爲false表示直接打開現有的Excel文檔
{
handler.OpenOrCreate();
//獲得Worksheet對象
Worksheet sheet = handler.GetWorksheet("TestSheet");

//圖片地址
string filePath = string.Format("{0}test.png", AppDomain.CurrentDomain.BaseDirectory);

//從第1行第5列插入圖片
Picture pic = handler.AddImage(sheet, filePath, 1, 5);


handler.Save();
}
}
效果如下圖:
3ExcelHandler 類完整源碼
/* ***********************************************
* Author:          Raymond Tang
* Email:           [email protected]
* Blog:               http://blog.tanging.net
* Created Time:    2010-3-14 9:59:43
* Class:           Tanging.Interop.Excel.ExcelHandler
* ***********************************************/

using System;
using System.IO;
using System.Reflection;
using System.Text;
using Xls = Microsoft.Office.Interop.Excel;
using System.Data;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Tanging.Interop.Excel
{
/// <summary>
/// Excel處理類
/// </summary>
/// <remarks>可以用於創建Excel,操作工作表,設置單元格樣式對齊方式等,導入內存、數據庫中的數據表,插入圖片到Excel等</remarks>
public sealed class ExcelHandler : IDisposable
{
#region [構造函數]

/// <summary>
/// ExcelHandler的構造函數
/// </summary>
/// <param name="fileName">Excel文件名,絕對路徑</param>
public ExcelHandler(string fileName)
: this(fileName, false)
{

}

/// <summary>
/// 創建ExcelHandler對象,指定文件名以及是否創建新的Excel文件
/// </summary>
/// <param name="fileName">Excel文件名,絕對路徑</param>
/// <param name="createNew">是否創建新的Excel文件</param>
public ExcelHandler(string fileName, bool createNew)
{
this.FileName = fileName;
this.mCreateNew = createNew;
}

#endregion

#region [字段和屬性]

private static readonly object missing = Missing.Value;

private string mFileName;
/// <summary>
/// Excel文件名
/// </summary>
public string FileName
{
get { return mFileName; }
set { mFileName = value; }
}
/// <summary>
/// 是否新建Excel文件
/// </summary>
private bool mCreateNew;

private Xls.Application mApp;
/// <summary>
/// 當前Excel應用程序
/// </summary>
public Xls.Application App
{
get { return mApp; }
set { mApp = value; }
}

private Xls.Workbooks mAllWorkbooks;
/// <summary>
/// 當前Excel應用程序所打開的所有Excel工作簿
/// </summary>
public Xls.Workbooks AllWorkbooks
{
get { return mAllWorkbooks; }
set { mAllWorkbooks = value; }
}

private Xls.Workbook mCurrentWorkbook;
/// <summary>
/// 當前Excel工作簿
/// </summary>
public Xls.Workbook CurrentWorkbook
{
get { return mCurrentWorkbook; }
set { mCurrentWorkbook = value; }
}

private Xls.Worksheets mAllWorksheets;
/// <summary>
/// 當前Excel工作簿內的所有Sheet
/// </summary>
public Xls.Worksheets AllWorksheets
{
get { return mAllWorksheets; }
set { mAllWorksheets = value; }
}

private Xls.Worksheet mCurrentWorksheet;
/// <summary>
/// 當前Excel中激活的Sheet
/// </summary>
public Xls.Worksheet CurrentWorksheet
{
get { return mCurrentWorksheet; }
set { mCurrentWorksheet = value; }
}

#endregion

#region [初始化操作,打開或者創建文件]
/// <summary>
/// 初始化,如果不創建新文件直接打開,否則創建新文件
/// </summary>
public void OpenOrCreate()
{
this.App = new Xls.ApplicationClass();
this.AllWorkbooks = this.App.Workbooks;

if (!this.mCreateNew)//直接打開
{
if (!File.Exists(this.FileName))
{
throw new FileNotFoundException("找不到指定的Excel文件,請檢查路徑是否正確!", this.FileName);
}

this.CurrentWorkbook = this.AllWorkbooks.Open(this.FileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Xls.XlPlatform.xlWindows, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

}
else//創建新文件
{
if (File.Exists(this.FileName))
{
File.Delete(this.FileName);
}
this.CurrentWorkbook = this.AllWorkbooks.Add(Type.Missing);

}

this.AllWorksheets = this.CurrentWorkbook.Worksheets as Xls.Worksheets;
this.CurrentWorksheet = this.CurrentWorkbook.ActiveSheet as Xls.Worksheet;
this.App.DisplayAlerts = false;
this.App.Visible = false;
}
#endregion

#region [Excel Sheet相關操作等]

/// <summary>
/// 根據工作表名獲取Excel工作表對象的引用
/// </summary>
/// <param name="sheetName"></param>
/// <returns></returns>
public Xls.Worksheet GetWorksheet(string sheetName)
{
return this.CurrentWorkbook.Sheets[sheetName] as Xls.Worksheet;
}

/// <summary>
/// 根據工作表索引獲取Excel工作表對象的引用
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public Xls.Worksheet GetWorksheet(int index)
{
return this.CurrentWorkbook.Sheets.get_Item(index) as Xls.Worksheet;
}

/// <summary>
/// 給當前工作簿添加工作表並返回的方法重載,添加工作表後不使其激活
/// </summary>
/// <param name="sheetName"></param>
/// <returns></returns>
public Xls.Worksheet AddWorksheet(string sheetName)
{
return this.AddWorksheet(sheetName, false);
}

/// <summary>
/// 給當前工作簿添加工作表並返回
/// </summary>
/// <param name="sheetName">工作表名</param>
/// <param name="activated">創建後是否使其激活</param>
/// <returns></returns>
public Xls.Worksheet AddWorksheet(string sheetName, bool activated)
{
Xls.Worksheet sheet = this.CurrentWorkbook.Worksheets.Add(Type.Missing, Type.Missing, 1, Type.Missing) as Xls.Worksheet;
sheet.Name = sheetName;
if (activated)
{
sheet.Activate();
}
return sheet;
}

/// <summary>
/// 重命名工作表
/// </summary>
/// <param name="sheet">工作表對象</param>
/// <param name="newName">工作表新名稱</param>
/// <returns></returns>
public Xls.Worksheet RenameWorksheet(Xls.Worksheet sheet, string newName)
{
sheet.Name = newName;
return sheet;
}

/// <summary>
/// 重命名工作表
/// </summary>
/// <param name="oldName">原名稱</param>
/// <param name="newName">新名稱</param>
/// <returns></returns>
public Xls.Worksheet RenameWorksheet(string oldName, string newName)
{
Xls.Worksheet sheet = this.GetWorksheet(oldName);
return this.RenameWorksheet(sheet, newName);
}

/// <summary>
/// 刪除工作表
/// </summary>
/// <param name="sheetName">工作表名</param>
public void DeleteWorksheet(string sheetName)
{
if (this.CurrentWorkbook.Worksheets.Count <= 1)
{
throw new InvalidOperationException("工作簿至少需要一個可視化的工作表!");
}
this.GetWorksheet(sheetName).Delete();
}

/// <summary>
/// 刪除除參數sheet指定外的其餘工作表
/// </summary>
/// <param name="sheet"></param>
public void DeleteWorksheetExcept(Xls.Worksheet sheet)
{
foreach (Xls.Worksheet ws in this.CurrentWorkbook.Worksheets)
{
if (sheet != ws)
{
ws.Delete();
}
}
}


#endregion

#region [單元格,Range相關操作]

/// <summary>
/// 設置單元格的值
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="rowNumber">單元格行號</param>
/// <param name="columnNumber">單元格列號</param>
/// <param name="value">單元格值</param>
public void SetCellValue(Xls.Worksheet sheet, int rowNumber, int columnNumber, object value)
{
sheet.Cells[rowNumber, columnNumber] = value;
}

/// <summary>
/// 合併單元格
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="rowNumber1">第一個單元格行號</param>
/// <param name="columnNumber1">第一個單元格列號</param>
/// <param name="rowNumber2">結束單元格行號</param>
/// <param name="columnNumber2">結束單元格列號</param>
public void MergeCells(Xls.Worksheet sheet, int rowNumber1, int columnNumber1, int rowNumber2, int columnNumber2)
{
Xls.Range range = this.GetRange(sheet, rowNumber1, columnNumber1, rowNumber2, columnNumber2);
range.Merge(Type.Missing);
}

/// <summary>
/// 獲取Range對象
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="rowNumber1">第一個單元格行號</param>
/// <param name="columnNumber1">第一個單元格列號</param>
/// <param name="rowNumber2">結束單元格行號</param>
/// <param name="columnNumber2">結束單元格列號</param>
/// <returns></returns>
public Xls.Range GetRange(Xls.Worksheet sheet, int rowNumber1, int columnNumber1, int rowNumber2, int columnNumber2)
{
return sheet.get_Range(sheet.Cells[rowNumber1, columnNumber1], sheet.Cells[rowNumber2, columnNumber2]);
}
#endregion

#region [設置單元格、Range的樣式、對齊方式自動換行等]

/// <summary>
/// 自動調整,設置自動換行以及自動調整列寬
/// </summary>
/// <param name="range"></param>
public void AutoAdjustment(Xls.Range range)
{
range.WrapText = true;
range.AutoFit();
}

/// <summary>
/// 設置Range的單元格樣式
/// </summary>
/// <remarks>將各項值設置爲默認值</remarks>
/// <param name="range"></param>
public void SetRangeFormat(Xls.Range range)
{
this.SetRangeFormat(range, 11, Xls.Constants.xlAutomatic, Xls.Constants.xlColor1, Xls.Constants.xlLeft);
}

/// <summary>
/// 設置Range的單元格樣式
/// </summary>
/// <remarks>將各項值設置爲默認值</remarks>
/// <param name="sheet"></param>
/// <param name="rowNumber1"></param>
/// <param name="columnNumber1"></param>
/// <param name="rowNumber2"></param>
/// <param name="columNumber2"></param>
public void SetRangeFormat(Xls.Worksheet sheet, int rowNumber1, int columnNumber1, int rowNumber2, int columNumber2)
{
this.SetRangeFormat(sheet, rowNumber1, columnNumber1, rowNumber2, columNumber2, 11, Xls.Constants.xlAutomatic);
}

/// <summary>
/// 設置Range的單元格樣式
/// </summary>
/// <param name="sheet"></param>
/// <param name="rowNumber1">第一個單元格行號</param>
/// <param name="columnNumber1">第一個單元格列號</param>
/// <param name="rowNumber2">結束單元格行號</param>
/// <param name="columnNumber2">結束單元格列號</param>
/// <param name="fontSize"></param>
/// <param name="fontName"></param>
public void SetRangeFormat(Xls.Worksheet sheet, int rowNumber1, int columnNumber1, int rowNumber2, int columNumber2, object fontSize, object fontName)
{
this.SetRangeFormat(this.GetRange(sheet, rowNumber1, columnNumber1, rowNumber2, columNumber2), fontSize, fontName, Xls.Constants.xlColor1, Xls.Constants.xlLeft);
}

/// <summary>
/// 設置Range的單元格樣式
/// </summary>
/// <param name="range">Range對象</param>
/// <param name="fontSize">字體大小</param>
/// <param name="fontName">字體名稱</param>
/// <param name="color">字體顏色</param>
/// <param name="horizontalAlignment">水平對齊方式</param>
public void SetRangeFormat(Xls.Range range, object fontSize, object fontName, Xls.Constants color, Xls.Constants horizontalAlignment)
{
range.Font.Color = color;
range.Font.Size = fontSize;
range.Font.Name = fontName;
range.HorizontalAlignment = horizontalAlignment;
}




#endregion

#region [導入內存中的DataTable]


/// <summary>
/// 導入內存中的數據表到Excel中
/// </summary>
/// <remarks>直接導入到工作表的最起始部分</remarks>
/// <param name="sheet"></param>
/// <param name="headerTitle"></param>
/// <param name="showTitle"></param>
/// <param name="headers"></param>
/// <param name="table"></param>
public void ImportDataTable(Xls.Worksheet sheet, string headerTitle, bool showTitle, object[] headers, DataTable table)
{
this.ImportDataTable(sheet, headerTitle, showTitle, headers, 1, 1, table);
}

/// <summary>
/// 導入內存中的數據表到Excel中
/// </summary>
/// <remarks>直接導入到工作表的最起始部分,且不顯示標題行</remarks>
/// <param name="sheet"></param>
/// <param name="headers"></param>
/// <param name="table"></param>
public void ImportDataTable(Xls.Worksheet sheet, object[] headers, DataTable table)
{
this.ImportDataTable(sheet, null, false, headers, table);

}

/// <summary>
/// 導入內存中的數據表到Excel中
/// </summary>
/// <remarks>標題行每一列與DataTable標題一致</remarks>
/// <param name="sheet"></param>
/// <param name="table"></param>
public void ImportDataTable(Xls.Worksheet sheet, DataTable table)
{
List<string> headers = new List<string>();
foreach (DataColumn column in table.Columns)
{
headers.Add(column.Caption);
}
this.ImportDataTable(sheet, headers.ToArray(), table);
}


/// <summary>
/// 導入內存中的數據表到Excel中
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="headerTitle">表格標題</param>
/// <param name="showTitle">是否顯示錶格標題行</param>
/// <param name="headers">表格每一列的標題</param>
/// <param name="rowNumber">插入表格的起始行號</param>
/// <param name="columnNumber">插入表格的起始列號</param>
/// <param name="table">內存中的數據表</param>
public void ImportDataTable(Xls.Worksheet sheet, string headerTitle, bool showTitle, object[] headers, int rowNumber, int columnNumber, DataTable table)
{
int columns = table.Columns.Count;
int rows = table.Rows.Count;

int titleRowIndex = rowNumber;
int headerRowIndex = rowNumber;
Xls.Range titleRange = null;

if (showTitle)
{
headerRowIndex++;
//添加標題行,並設置樣式
titleRange = this.GetRange(sheet, rowNumber, columnNumber, rowNumber, columnNumber + columns - 1);
titleRange.Merge(missing);

this.SetRangeFormat(titleRange, 16, Xls.Constants.xlAutomatic, Xls.Constants.xlColor1, Xls.Constants.xlCenter);
titleRange.Value2 = headerTitle;
}

//添加表頭
int m = 0;
foreach (object header in headers)
{
this.SetCellValue(sheet, headerRowIndex, columnNumber + m, header);
m++;
}

//添加每一行的數據
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
sheet.Cells[headerRowIndex + i + 1, j + columnNumber] = table.Rows[i][j];
}
}

}

#endregion

#region [插入圖片到Excel中的相關方法]
/// <summary>
/// 插入圖片
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="imageFilePath">圖片的絕對路徑</param>
/// <param name="rowNumber">單元格行號</param>
/// <param name="columnNumber">單元格列號</param>
/// <returns></returns>
public Xls.Picture AddImage(Xls.Worksheet sheet, string imageFilePath, int rowNumber, int columnNumber)
{
Xls.Range range = this.GetRange(sheet, rowNumber, columnNumber, rowNumber, columnNumber);
range.Select();
Xls.Pictures pics = sheet.Pictures(missing) as Xls.Pictures;
Xls.Picture pic = pics.Insert(imageFilePath, missing);
pic.Left = (double)range.Left;
pic.Top = (double)range.Top;
return pic;
}

/// <summary>
/// 插入圖片
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="imageFilePath">圖片的絕對路徑</param>
/// <param name="rowNumber">單元格行號</param>
/// <param name="columnNumber">單元格列號</param>
/// <param name="width">圖片的寬度</param>
/// <param name="height">圖片的高度</param>
/// <returns></returns>
public Xls.Picture AddImage(Xls.Worksheet sheet, string imageFilePath, int rowNumber, int columnNumber, double width, double height)
{
Xls.Picture pic = this.AddImage(sheet, imageFilePath, rowNumber, columnNumber);
pic.Width = width;
pic.Height = height;
return pic;
}

///// <summary>
///// 插入圖片
///// </summary>
///// <remarks>從流中讀取圖片</remarks>
///// <param name="sheet"></param>
///// <param name="imageStream"></param>
///// <param name="x"></param>
///// <param name="y"></param>
///// <param name="width"></param>
///// <param name="height"></param>
///// <returns></returns>
//public Xls.Picture AddImage(Xls.Worksheet sheet, Stream imageStream, int x, int y, double width, double height)
//{

//}

#endregion

#region [保存Excel]

/// <summary>
/// 保存Excel
/// </summary>
public void Save()
{
if (this.mCreateNew)
{
this.SaveAs(this.FileName);
}
else
{
this.CurrentWorkbook.Save();
}

//this.SaveAs(this.FileName);
}

/// <summary>
/// 保存Excel
/// </summary>
/// <param name="filePath">文件的絕對路徑</param>
public void SaveAs(string filePath)
{
this.CurrentWorkbook.SaveAs(filePath, Xls.XlFileFormat.xlWorkbookNormal, missing, missing, missing,
missing, Xls.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
}

#endregion


#region [公共幫助方法]
/// <summary>
/// 更新Uri
/// </summary>
public string UpdateUri
{
get
{
return "http://hi.baidu.com/1987raymond";
}
}

#endregion

#region [IDisposable 成員]
/// <summary>
/// 對象銷燬時執行的操作
/// </summary>
public void Dispose()
{

//this.CurrentWorkbook.Close(true, this.FileName, missing);
Marshal.FinalReleaseComObject(this.CurrentWorkbook);
this.CurrentWorkbook = null;

this.App.Quit();
Marshal.FinalReleaseComObject(this.App);
this.App = null;

System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}

#endregion
}
}
發佈了10 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章