ASP.NET產生Excel的幾種方式
還記得剛跨進程式設計這個領域的時候,當時有處理到一個問題,使用者在Web上面產生Excel檔造成記憶體崩潰的問題。查看了程式發現那時候的開發方式是使用【 Excel 物件模型來存取】,但這種方式主要是運用在單機使用上,若在Web上面使用常常會有很多問題產生,例如 : 記憶體無法釋放等問題。
那時候剛進行,完全不知道該如何解決,老闆只好請我跟微軟詢問該如何解決,得到的答案確是Microsoft 不建議在Server端使用直接存取 Excel 物件模型的方式來控制 Excel 檔案,後來因為某些因素就離開了該公司,也沒有解決此問題,這個問題變成我寫程式以來最挫折的事情。但很幸運的是,後來所接觸的程式開發,除了報表外(可以透過ReportViewer幫我們產生),要匯出Excel的檔案都不是很複雜的,因此都可以使用Html表格畫表在透過改變ContentType的方式來產生,日子久了也漸漸淡忘這個悲慘的往事 ~"~。
這陣子再翻以前廠商開發的程式的時候發現了另一種使用方式NPOI Library,這是由幾個佛心來的開發者共同開發出來給大家使用的,詳細資訊可以參考MSDN的學習園地。下面大概說明一下三種常見的轉出Excel方式。
1. 透過改變ContentType為Excel標頭檔的方式,這個方法是最快速也最簡單,完全不需要使用使用額外的Library就可以轉出Excel檔,但缺點就是彈性很小,因為是使用HTML偽裝成Excel檔,若有比較特殊的需求就比較難達成,且轉出的檔案在新版的Office上面開啟會跳出警告訊息如下圖。
2. 使用Excel物件模型,這個就是我心中的痛~"~,但是由於在Web使用上不太適合,且有其它的替代方案,因此我就沒有深入研究了,關於Lock的更多的解決方是可以自行參考如何 回收 被 VB 及 C# 呼叫的 Excel 應用程式,簡單的使用方式如下。
3. 使用NPOI Library,下面的使用方式所產生檔案是跟上面一模一樣的,這只是一個簡單的範例,NPOI功能強大且並沒有使用到 Excel 的任何東西,它直接深入 OLE Compound Document (複合文件)格式內去存取資料,也可以直接控制到各種儲存格的資訊(顏色,儲存格格式與樣式等),並將它物件導向化,外部開發人員只需要利用 NPOI 提供的屬性就可以控制 Office 格式的檔案資料,且更不會有Lock的問題。
這樣比較下來NPOI幾乎跟上面兩種方使比起來幾乎是零缺點,但是我還是不常使用到它~"~,因為說真的,專案開發時程的限制,讓自己沒辦法追求到完美,有時候一些很簡單的清單,我就會用偷懶的方式Response.Write來處理了。
本文範例 :
ExprotExcel.zip
那時候剛進行,完全不知道該如何解決,老闆只好請我跟微軟詢問該如何解決,得到的答案確是Microsoft 不建議在Server端使用直接存取 Excel 物件模型的方式來控制 Excel 檔案,後來因為某些因素就離開了該公司,也沒有解決此問題,這個問題變成我寫程式以來最挫折的事情。但很幸運的是,後來所接觸的程式開發,除了報表外(可以透過ReportViewer幫我們產生),要匯出Excel的檔案都不是很複雜的,因此都可以使用Html表格畫表在透過改變ContentType的方式來產生,日子久了也漸漸淡忘這個悲慘的往事 ~"~。
這陣子再翻以前廠商開發的程式的時候發現了另一種使用方式NPOI Library,這是由幾個佛心來的開發者共同開發出來給大家使用的,詳細資訊可以參考MSDN的學習園地。下面大概說明一下三種常見的轉出Excel方式。
1. 透過改變ContentType為Excel標頭檔的方式,這個方法是最快速也最簡單,完全不需要使用使用額外的Library就可以轉出Excel檔,但缺點就是彈性很小,因為是使用HTML偽裝成Excel檔,若有比較特殊的需求就比較難達成,且轉出的檔案在新版的Office上面開啟會跳出警告訊息如下圖。
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=Excel.xls");
Response.ContentType = "application/vnd.ms-excel";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
Response.Write("<style type='text/css'>table{ vnd.ms-excel.numberformat:@;font-family:%u5FAE%u8EDF%u6B63%u9ED1%u9AD4;font-size:10pt; }</style>");
Response.Write("");
Response.Write("");
foreach (DataRow row in dt.Rows)
{
Response.Write("");
Response.Write("");
Response.Write("");
Response.Write("");
Response.Write("");
}
Response.Write("<table border="1"><tr><td>Name</td><td>Birthday</td><td>Age</td></tr>");
Response.Write("<tr>");
Response.Write("<td>" + row["Name"].ToString() + "</td>");
Response.Write("<td>" + row["Birthday"].ToString() + "</td>");
Response.Write("<td>" + row["Age"].ToString() + "</td>");
Response.Write("</tr>");
Response.Write("</table>");
Response.End();
2. 使用Excel物件模型,這個就是我心中的痛~"~,但是由於在Web使用上不太適合,且有其它的替代方案,因此我就沒有深入研究了,關於Lock的更多的解決方是可以自行參考如何 回收 被 VB 及 C# 呼叫的 Excel 應用程式,簡單的使用方式如下。
protected void Button2_Click(object sender, EventArgs e)
{
string execelfullpath = Server.MapPath("~/Excel.xls");
Microsoft.Office.Interop.Excel.Application xlapp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wbook = xlapp.Workbooks.Add(1);
Microsoft.Office.Interop.Excel.Worksheet wsheet = (Microsoft.Office.Interop.Excel.Worksheet)wbook.Worksheets[1];
wsheet.Name = "Sheet Name";
Microsoft.Office.Interop.Excel.Range range;
//標題列
wsheet.Cells[1, 1] = "Name";
wsheet.Cells[1, 2] = "Birthday";
wsheet.Cells[1, 3] = "Age";
FormateExcelStyle((Microsoft.Office.Interop.Excel.Range)wsheet.Cells[1, 1]);
FormateExcelStyle((Microsoft.Office.Interop.Excel.Range)wsheet.Cells[1, 2]);
FormateExcelStyle((Microsoft.Office.Interop.Excel.Range)wsheet.Cells[1, 3]);
int introw = 2;
foreach (DataRow dr in dt.Rows)
{
wsheet.Cells[introw, 1] = dr["Name"].ToString();
wsheet.Cells[introw, 2] = dr["Birthday"].ToString();
wsheet.Cells[introw, 3] = dr["Age"].ToString();
FormateExcelStyle((Microsoft.Office.Interop.Excel.Range)wsheet.Cells[introw, 1]);
FormateExcelStyle((Microsoft.Office.Interop.Excel.Range)wsheet.Cells[introw, 2]);
FormateExcelStyle((Microsoft.Office.Interop.Excel.Range)wsheet.Cells[introw, 3]);
introw++;
}
if (File.Exists(execelfullpath)) File.Delete(execelfullpath);
wbook.SaveAs(execelfullpath,
Microsoft.Office.Interop.Excel.XlFileFormat.xlXMLSpreadsheet,
Missing.Value,
Missing.Value,
false,
false,
Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
Missing.Value,
Missing.Value,
Missing.Value,
Missing.Value,
Missing.Value
);
KillExcel(xlapp);
Response.Redirect("Excel.xls");
}
//儲存格格式
private void FormateExcelStyle(Microsoft.Office.Interop.Excel.Range range)
{
range.Font.Name = "微軟正黑體";
range.BorderAround(XlLineStyle.xlContinuous, XlBorderWeight.xlThin, XlColorIndex.xlColorIndexAutomatic, null);
}
//刪除Excel執行個體,解決Excel發生Lock的問題
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
static void KillExcel(Microsoft.Office.Interop.Excel.Application m_objExcel)
{
if (m_objExcel != null)
{
int lpdwProcessId;
GetWindowThreadProcessId(new IntPtr(m_objExcel.Hwnd), out lpdwProcessId);
System.Diagnostics.Process.GetProcessById(lpdwProcessId).Kill();
System.Threading.Thread.Sleep(2000);
}
}
3. 使用NPOI Library,下面的使用方式所產生檔案是跟上面一模一樣的,這只是一個簡單的範例,NPOI功能強大且並沒有使用到 Excel 的任何東西,它直接深入 OLE Compound Document (複合文件)格式內去存取資料,也可以直接控制到各種儲存格的資訊(顏色,儲存格格式與樣式等),並將它物件導向化,外部開發人員只需要利用 NPOI 提供的屬性就可以控制 Office 格式的檔案資料,且更不會有Lock的問題。
HSSFWorkbook workbook = new HSSFWorkbook();
using (MemoryStream ms = new MemoryStream())
{
// 新增試算表。
ISheet sheet = workbook.CreateSheet("Sheet Name");
// 儲存格字型
NPOI.SS.UserModel.IFont font = workbook.CreateFont();
font.FontName = "微軟正黑體";
// 建立儲存格樣式。
ICellStyle style = workbook.CreateCellStyle();
style.SetFont(font);
style.BorderBottom = NPOI.SS.UserModel.BorderStyle.THIN;
style.BottomBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index;
style.BorderLeft = NPOI.SS.UserModel.BorderStyle.THIN;
style.LeftBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index;
style.BorderRight = NPOI.SS.UserModel.BorderStyle.THIN;
style.RightBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index;
style.BorderTop = NPOI.SS.UserModel.BorderStyle.THIN;
style.TopBorderColor = NPOI.HSSF.Util.HSSFColor.BLACK.index;
//插入標題列
IRow row = sheet.CreateRow(0);
row.CreateCell(0).SetCellValue("Name");
row.CreateCell(1).SetCellValue("Birthday");
row.CreateCell(2).SetCellValue("Age");
row.Cells[0].CellStyle = style;
row.Cells[1].CellStyle = style;
row.Cells[2].CellStyle = style;
int i = 1;
foreach (DataRow dr in dt.Rows)
{
row = sheet.CreateRow(i);
row.CreateCell(0).SetCellValue(dr["Name"].ToString());
row.CreateCell(1).SetCellValue(dr["Birthday"].ToString());
row.CreateCell(2).SetCellValue(dr["Age"].ToString());
row.Cells[0].CellStyle = style;
row.Cells[1].CellStyle = style;
row.Cells[2].CellStyle = style;
i++;
}
workbook.Write(ms);
Response.AddHeader("Content-Disposition", string.Format("attachment; filename=Excel.xls"));
Response.BinaryWrite(ms.ToArray());
}
workbook = null;
這樣比較下來NPOI幾乎跟上面兩種方使比起來幾乎是零缺點,但是我還是不常使用到它~"~,因為說真的,專案開發時程的限制,讓自己沒辦法追求到完美,有時候一些很簡單的清單,我就會用偷懶的方式Response.Write來處理了。
本文範例 :
ExprotExcel.zip

留言
張貼留言
您好,我是 Lawrence,這裡是我的開發筆記的網誌,如果你對我的文章有任何疑問或者有錯誤的話,歡迎留言讓我知道。