感谢
pc1024
在
CSDN
上的博客,文中很多是参考他的博客
在
ASP.NET
应用程序常常会遇到需要从
Excel
文件中读取数据或将数据写入
Excel
的需求。一般来讲,在
ASP.NET
中读写
Excel
文件有四种解决方案。
1
使用
OLE DB
使用
OLE DB
可以以查询数据库的方式来读取
Excel
文件,因为在某种程度上
Excel
表格可以看成是一张一张的数据表。其二者的主要区别在于所使用的数据引擎不一样。使用
OLE DB
访问
Excel
的要点是计算机上必须具有
Microsoft Access Data Component 2.6(MADC2.6)
以上版本,同时在连接字符串上必须声明
“Extended Properties=Excel 8.0”
,这里的指定
Excel
版本号如果高于
8.0
可能会出错,所以一般来讲必须使用
Excel 8.0
。
例如下面的实现代码:
//
创建一个数据链接
string strCon = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source = c://sample.xls;Extended Properties=Excel 8.0" ;
OleDbConnection myConn = new OleDbConnection ( strCon ) ;
string strCom = " SELECT * FROM [Sheet1$] " ;
myConn.Open ( ) ;
//
打开数据链接,得到一个数据集
OleDbDataAdapter myCommand = new OleDbDataAdapter ( strCom , myConn ) ;
//
创建一个
DataSet
对象
myDataSet = new DataSet ( ) ;
//
得到自己的
DataSet
对象
myCommand.Fill ( myDataSet , "[Sheet1$]" ) ;
//
关闭此数据链接
myConn.Close ( ) ;
使用这种解决方案的优点是不需要其他的服务器组件,部署非常方便,但是其缺点也是明显的,用它来读取
Excel 2003
格式以上的文件会存在数据丢失的情况,而且也无法生成
Excel
文件。
2
使用
Office
主互操作程序集
另外一种解决方案是使用
Office
主互操作程序集,采用这种方式需要在服务器上安装
Office 2003
。但是能够比较精细的控制
Excel
文件的方方面面,包括格式、字体、颜色等等。
下面的代码演示了如何读取
Excel
文件中某个单元格的值:
示例:
using
System;
using
Microsoft.Office.Interop.Excel;
using
System.Reflection;
using
System.Data;
public
class ExcelApp
{
private static ApplicationClass xApp;
public static string TransferToExcelFile(string parentPath, string fileName, System.Data.DataTable data)
{
if (xApp == null)
{
xApp = new ApplicationClass();
//xApp.Visible = true;
}
if (xApp != null)
{
try
{
WorkbookClass xBook = xApp.Workbooks.Add(Missing.Value) as WorkbookClass;
if (xBook != null)
{
//WorksheetClass xSheet = xBook.Sheets[1] as WorksheetClass;
Worksheet xSheet = xApp.ActiveSheet as Worksheet;
Range range = null;
if (xSheet != null)
{
int columnCount = data.Columns.Count;
for (int i = 0; i < columnCount; i++)
{
range = (Range)xSheet.Cells[1, i + 1];
if (range != null)
//range1.Value2 = "rang";
range.Value2 = data.Columns[i].ColumnName;
}
int rowsCount = data.Rows.Count;
for (int i = 0; i < rowsCount; i++)
{
for (int col = 0; col < columnCount; col++)
{
range = (Range)xSheet.Cells[i + 2, col + 1];
if (range != null)
range.Value2 = (data.Rows[i][col] == null) ? "" : data.Rows[i][col].ToString();
}
}
}
fileName = fileName + DateTime.Now.Ticks.ToString() + ".xlsx";
string savePath = parentPath + "//" + fileName;
xBook.SaveAs(savePath,
Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
xBook.Close(Missing.Value, Missing.Value, Missing.Value);
xSheet = null;
xBook = null;
return fileName;
// xApp.Quit();
// xApp = null;
}
}
catch
{
return "";
}
finally
{
GC.Collect();
}
}
return "";
}
~ExcelApp()
{
if (xApp != null)
{
xApp.Quit();
xApp = null;
GC.Collect();
}
}
}
实际上对于
ASP.NET
来讲,这并不是一个很好的解决方案,其原因是这个解决方案将客户端的组件用到了服务器上,这往往会带来很多的问题,如果在处理一个
Excel
文件的时候出错,那么整个线程就会死在那里,服务器上的
Excel
进程无法重启动,
Excel
文件无法删除,后面的
Excel
文件也无法处理,只能重启服务器,还有如果使用单例模式生成
ExcelApp
,如上面的代码,如何有效地控制并发性也是很大的问题。
3
使用
ServerDocument
在上一个解决方案中,使用
Office
主互操作程序集存在很大的问题,究其原因是因为将本应在客户端使用的
Office
组件用在了服务器上导致的,因为这些
Office
组件在设计之初就没有考虑在服务中调用的情况。对于在服务器上使用
Excel
文件,微软推荐的解决方案是使用
ServerDocument
。
在具有
Microsoft Visual Studio 2005 Tools for the Microsoft Office System
自定义的
Microsoft Office Word 2003
文档或
Microsoft Office Excel 2003
工作簿中,可以将数据存储在嵌入的数据岛中,无需启动
Excel
或
Word
即可访问数据岛。
数据岛是一个
XML
文档,其中包含
Office
文档中嵌入的数据;无需实例化
Office
文档即可访问该
XML
文档。数据实际存在于两个地方,即文档和单独的嵌入数据岛中。在数据岛与文档之间使用了数据绑定以使它们保持同步。如果服务器上运行的代码修改了数据岛,则在文档打开并且文档中的代码运行时,
Office
文档会与数据岛进行同步。
此模型具有以下几项优势:
l
可以将验证代码添加到独立于文档的数据中。通过将验证与文档分离,可以将数据验证代码移植到其他文档中。
l
数据岛使用可脱机使用的数据填充。当文档中的缓存数据项包含数据时,该文档将与数据岛进行交互。
l
由于可以从外部访问数据岛,因此无需实例化
Office
就可以修改文档中嵌入的数据,从而支持服务器上文档的快速批处理。但是,只能访问缓存中的数据,而不是文档中的所有数据。
l
需要添加
Microsoft.VisualStudio.Tools.Applications.Runtime;
引用
下面的代码分别演示了如何使用
ServerDocument
访问数据和从数据生成
Excel
文档:
string
expenseDoc = @"C:/ExpenseDocuments/Expenses0105.xls";
ServerDocument sd1 = null;
try
{
sd1 = new ServerDocument(expenseDoc);
CachedDataHostItem dataHostItem1 = sd1.CachedData.HostItems["DataNamespace.DataWorksheet"];
CachedDataItem dataItem1 = dataHostItem1.CachedData["DataCache"];
System.IO.StringReader schemaReader = new System.IO.StringReader(dataItem1.Schema);
System.IO.StringReader xmlReader = new System.IO.StringReader(dataItem1.Xml);
ExpenseData.ReadXmlSchema(schemaReader);
ExpenseData.ReadXml(xmlReader);
}
finally
{
if (sd1 != null)
{
sd1.Close();
}
}
代码
7-4
string
name = @"C:/Documents/WordApplication3.doc";
System.IO.FileStream fileStream = null;
byte[] bytes = null;
try
{
fileStream = new System.IO.FileStream(
name, System.IO.FileMode.Open, System.IO.FileAccess.Read);
bytes = new byte[(int)fileStream.Length];
fileStream.Read(bytes, 0, (int)fileStream.Length);
}
finally
{
if (fileStream != null)
{
fileStream.Close();
}
}
ServerDocument sd1 = null;
try
{
sd1 = new ServerDocument(bytes, name);
// Your data manipulation code goes here.
sd1.Save();
bytes = sd1.Document;
// If you have a Word document, use the MIME string:
Response.ContentType = "application/msword";
// If you have an Excel workbook, use the MIME string:
//Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-disposition", "filename=" + name);
Response.Write(sd1);
}
finally
{
if (sd1 != null)
{
sd1.Close();
}
}
代码
7-5
相对来说,这是一个比较理想的解决方案,但是使用该方案有如下几个限制:
l
客户端必须安装
.NET Framework 2.0
、
Office Tools for Visual Studio
运行时和
Office 2003
。
l
开发嵌入于文档中的程序集,用于同步视图和数据岛中的数据,例如用数据岛数据中的某个值更新某单元格中的值,或者用某单元格中的值更新数据岛中的值。
l
使用专用的
Excel
模板。
4
对于
Office 2007
的
OpenXML
格式使用
OpenXML SDK
如果决定
ASP.NET
应用程序仅处理
Office 2007
生成的
OpenXML
格式文档,那么使用
OpenXML SDK
是一个更好的主意,因为它不需要在服务器上安装
Office
,对客户端也没有任何要求,只要用的是
OpenXML
格式的文档就可以了,因为
OpenXML
格式已提交国际标准化组织,所以,用户可以使用支持
OpenXML
的任何应用程序读取和编辑该文档。
使用该方案需要下载
OpenXML SDK
并使用其进行开发,目前该
SDK
还只是一个
CTP
版本。
具体的
SDK
和参考资料可以到
MSDN
上搜索