关于excel在asp.net中使用
.Net使用excel表有两种方式,
一种是通过oldb来进行连接,把excel表作为数据库来处理。
另一种则是通过引用excel对象,进行对象编程来,调用excel的函数方法。
总的来说,第一种很方便,但缺乏变化,第二种很灵活,但是,缺乏规律性。
具体使用中,看来还是要看情况来操作。
第一种情况,是不需要asp.net作什么额外动作,
第二种情况,需要使用tblim.exe来将excel的com转换成为托管主件,才能在import namespace。
其实,也可以有vs.net进行转换,更为方便。
一旦引用excel namespace,其后的编程就能根据excel帮助里面的编程指南,调用它的对象,方法,属性等等。
我在想,今后把它写成一个webservice可以随意从数据库中,将数据倒出来。
the following content updated on 2005-11-23
===================================
其实,我们经常适用到的还是第二种模式。
最近我接到一个项目用到的导入Excel数据的问题,我把我的经验和代码共享出来。
这个项目的Excel的导入假定条件是:
1.有几个range是固定值
2.有一个整块的数据内容区(range)
3.可能有多个符合上面1、2要求,但具体格式不一致的Excel模板。
4.几个不同模板可能导入不同数据库表。
当时由于正在看DOTTEXT代码,对其中Provider这种模式非常感兴趣,考虑了一番认为这个Excel导入项目可以借用Provider模式。
对Provider模式的解释
无论源对象是什么,通过IProvider接口,我们可以得到一个较为统一的对象,也就是说同IProvider,我们屏蔽对源数据对象的处理细节,而完成得到一个符合我们要求的目的对象。
--这段解释完全是自己的理解和体会,请大家斧正
综合考虑后,我觉得我应该有一个对象来描述目前Excel格式内容,比如:描述固定range,描述不固定的数据块的开始地方(range),从第几列到第几列是数据区,同时定义输入限制数据类型。
我命名这个对象为:ExcelMapDB
/// <summary>
/// ExcelMapDB 的摘要说明。
/// Author:King astar
/// Date:2005-10-27
/// Description:用来描述Excel列对应数据列的关系
/// </summary>
///
[Serializable]
public class ExcelMapDB
{
private bool _isfixed = false;
/// <summary>
/// 是否是固定列
/// </summary>
///
[XmlAttribute("IsFixed")]
public bool IsFixed
{
get{return _isfixed;}
set{_isfixed = value;}
}
private String _rowshowName="";
/// <summary>
/// 对应的datarow的显示名称是什么
/// </summary>
///
[XmlAttribute("RowShowName")]
public String RowShowName
{
get{return _rowshowName;}
set{_rowshowName = value;}
}

private String _rowName;
/// <summary>
/// 对应的datarow的列名是什么
/// </summary>
///
[XmlAttribute("RowName")]
public String RowName
{
get{return _rowName;}
set{_rowName = value;}
}
private String _excelRangeName;
/// <summary>
/// 如果是固定列则直接读取rangName;
/// eg. A2 B3 etc
.
/// </summary>
///
[XmlAttribute("ExcelRangeName")]
public String ExcelRangeName
{
get{return _excelRangeName;}
set{_excelRangeName = value;}
}
private int _offSetStartRange;
/// <summary>
/// 如果是相对列,则使用相对开始列的Y轴的距离来得到值
/// </summary>
///
[XmlAttribute("OffYSetStartRange")]
public int OffYSetStartRange
{
get{return _offSetStartRange;}
set{_offSetStartRange = value;}
}
public ExcelMapDB()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
} 序列化对象的XML
<?xml version="1.0" encoding="utf-8"?>2
<ExcelMapDbRelation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" DataTableProviderType="QAComponents.Codes.Provider.BaseDataTableProvider, QAComponents.Codes" ExcelStartRangeName="A6" ConvertorType="QAComponents.Codes.Convertor.BaseConvertor, QAComponents.Codes">3
<RelationItems>4
<ExcelMapDB IsFixed="true" RowName="Temp1" ExcelRangeName="D4" OffYSetStartRange="0" />5
<ExcelMapDB IsFixed="true" RowName="Temp2" ExcelRangeName="L4" OffYSetStartRange="0" />6
<ExcelMapDB IsFixed="true" RowName="Temp3" ExcelRangeName="T4" OffYSetStartRange="0" />7
<ExcelMapDB IsFixed="false" RowName="SerialNo" ExcelRangeName="" OffYSetStartRange="0" />8
<ExcelMapDB IsFixed="false" RowName="Ith1" ExcelRangeName="" OffYSetStartRange="1" />9
<ExcelMapDB IsFixed="false" RowName="Vf1" ExcelRangeName="" OffYSetStartRange="2" />10
<ExcelMapDB IsFixed="false" RowName="Pf1" ExcelRangeName="3" OffYSetStartRange="3" />11
<ExcelMapDB IsFixed="false" RowName="ImPf1" ExcelRangeName="4" OffYSetStartRange="4" />12
<ExcelMapDB IsFixed="false" RowName="SE1" ExcelRangeName="5" OffYSetStartRange="5" />13
<ExcelMapDB IsFixed="false" RowName="SMSR1" ExcelRangeName="6" OffYSetStartRange="6" />14
<ExcelMapDB IsFixed="false" RowName="A1" ExcelRangeName="7" OffYSetStartRange="7" />15
<ExcelMapDB IsFixed="false" RowName="B1" ExcelRangeName="8" OffYSetStartRange="8" />16
17
18
<ExcelMapDB IsFixed="false" RowName="Ith12" ExcelRangeName="9" OffYSetStartRange="9" />19
<ExcelMapDB IsFixed="false" RowName="Vf2" ExcelRangeName="10" OffYSetStartRange="10" />20
<ExcelMapDB IsFixed="false" RowName="Pf2" ExcelRangeName="11" OffYSetStartRange="11" />21
<ExcelMapDB IsFixed="false" RowName="ImPf2" ExcelRangeName="12" OffYSetStartRange="12" />22
<ExcelMapDB IsFixed="false" RowName="SE2" ExcelRangeName="13" OffYSetStartRange="13" />23
<ExcelMapDB IsFixed="false" RowName="SMSR2" ExcelRangeName="14" OffYSetStartRange="14" />24
<ExcelMapDB IsFixed="false" RowName="A2" ExcelRangeName="15" OffYSetStartRange="15" />25
<ExcelMapDB IsFixed="false" RowName="B2" ExcelRangeName="16" OffYSetStartRange="16" />26
27
<ExcelMapDB IsFixed="false" RowName="Sen" ExcelRangeName="17" OffYSetStartRange="17" />28
<ExcelMapDB IsFixed="false" RowName="Vbr" ExcelRangeName="18" OffYSetStartRange="18" />29
<ExcelMapDB IsFixed="false" RowName="Vop" ExcelRangeName="19" OffYSetStartRange="19" />30
<ExcelMapDB IsFixed="false" RowName="Iop" ExcelRangeName="20" OffYSetStartRange="20" />31
<ExcelMapDB IsFixed="false" RowName="Io" ExcelRangeName="21" OffYSetStartRange="21" />32
<ExcelMapDB IsFixed="false" RowName="Gain" ExcelRangeName="22" OffYSetStartRange="22" />33
<ExcelMapDB IsFixed="false" RowName="FileNo" ExcelRangeName="23" OffYSetStartRange="23" /> 34
35

36
</RelationItems>37
</ExcelMapDbRelation>
接着我定义Excel对应数据表的关系对象
这个对象还要考虑,它用什么转换器来转换
/// <summary>2
/// ExcelMapDB 的摘要说明。3
/// Author:King astar4
/// Date:2005-10-275
/// Description:用来描述Excel表对应数据表的关系6
/// </summary>7
public class ExcelMapDbRelation8
{9
private ExcelMapDB[] _relationItems;10
[XmlArray("RelationItems")]11
public ExcelMapDB[] RelationItems12
{13
get{return _relationItems;}14
set{_relationItems = value;}15
}16

17
private String _dataTableProviderType = "BaseDataTableProvider";18
/// <summary>19
/// 数据提供者类型名称20
/// </summary>21
[XmlAttribute("DataTableProviderType")]22
public String DataTableProviderType23
{24
get{return _dataTableProviderType;} 25
set{_dataTableProviderType = value;}26
}27

28
private String _excelStartRangeName;29
/// <summary>30
/// 开始的范围;31
/// eg. A2 B3 etc
.32
/// </summary>33
/// 34
[XmlAttribute("ExcelStartRangeName")]35
public String ExcelStartRangeName36
{37
get{return _excelStartRangeName;}38
set{_excelStartRangeName = value;}39
} 40

41
/// <summary>42
/// 取得数据提供者对象43
/// </summary>44
[XmlIgnore]45
public IDataTableProvider TableProvider46
{47
get48
{49
IDataTableProvider dprovider =null;50
if(DataTableProviderType!=null)51
{52
dprovider = (IDataTableProvider)System.Activator.CreateInstance(Type.GetType(DataTableProviderType));53
}54
return dprovider;55
}56
57

58

59
}60

61
private String _convertorType ;62
/// <summary>63
/// 转换器类型名称64
/// </summary>65
[XmlAttribute("ConvertorType")]66
public String ConvertorType67
{68
get{return _convertorType;}69
set{_convertorType = value;}70
}71

72
/// <summary>73
/// 取得转换器对象74
/// </summary>75
[XmlIgnore]76
public IConvertor DataConvertor77
{78
get79
{80
IConvertor convertor =null;81
if(ConvertorType!=null)82
{83
convertor = (IConvertor)System.Activator.CreateInstance(Type.GetType(ConvertorType));84
}85
return convertor;86
}87
88

89

90
}91

92
93

94
constructor102
}103
作了这些基础工作后,我考虑可以来写转换器的工作了,这部分工作是核心工作,在这部分数据会从Excel导入到数据库去。
看看接口
/// <summary>2
/// IConvertor 的摘要说明。3
/// </summary>4
public interface IConvertor5
{6

7
void Execute(DataTable dt,ExcelMapDB[] excelMapdbs,String fileName,String excelStartRangeName,int IdentityID);8
}只有一个Excute的方法参数分别是Excel对应关系对象,Excel文件路径,excel开始range名称,此Excel表唯一ID
然后,我写了一个BaseConvertor, 主要工作就是打开Excel文件,按照定义的Excel列与数据表列对应关系对象来抓数据,并导入到数据库中去。
请参看代码(注意:打开Excel的方法是Excel11.0版本,office 2003)

2
/// <summary>3
/// BaseConvertor 的摘要说明。4
/// Author:King astar5
/// Date:2005-10-276
/// Description:核心类,将Excel数据导入数据库,是基类,可以继承7
/// </summary>8
public class BaseConvertor : IConvertor9
{10

11
variable26

27

28
public BaseConvertor()29
{30
//31
// TODO: 在此处添加构造函数逻辑32
//33
}34

35
IConvertor 成员60

61
public virtual void Openexcel(String fileName)62
{63
string FileName = @fileName;64
FileName = FileName.Replace("/",@"\");65
FileName = FileName.Replace(@"\\",@"\");66

67

68
if(!System.IO.File.Exists(FileName))69
throw new Exception("["+FileName+"]不存在!");70

71
try72
{73
app = new Excel.ApplicationClass();74
}75
catch(System.Exception ex)76
{77
new Exception("无法实例化Excel对象;<br/>details:<hr size=1/>"+ex.Message);78
}79
app.DisplayAlerts = false;80

81
// //app.UserControl = true;82
wbs = app.Workbooks;83
try84
{85
86
wbc = wbs.Open(FileName,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt,_objOpt); 87
}88
catch(System.Exception ex)89
{90
throw new Exception("无法正确打开文件;<br/>details:<hr size=1/>"+ex.Message);91
}92

93

94
}95
public virtual void Dispose()96
{97
fixedRange =null;98
firstRange = null;99
ws = null;100
wbc = null;101
102
if(wbs!=null)103
{104
wbs.Close ();105
wbs = null;106
}107
if(app!=null)108
{109
app.Quit();110
app =null;111
}112
113
114
115

116
}117

118
public System.Data.DataTable FillTable(System.Data.DataTable myTable,QAComponents.Codes.Configs.ExcelMapDB[] excelMapdbs,string excelStartRangeName)119
{120
ws= (Excel.Worksheet)wbc.Worksheets.get_Item(1);121
firstRange = ws.get_Range(excelStartRangeName.Trim().ToUpper(),this._objOpt);122
int x =0;123
x = Convert.ToInt32(excelStartRangeName.Trim().ToUpper().Substring(124
1,1));125
//开始循环126
while(firstRange.Value2!=null&&firstRange.Value2.ToString()!="")127
{128
129
System.Data.DataRow dr = myTable.NewRow();130
131
for(int i=0;i<excelMapdbs.Length;i++)132
{133
try134
{135
if(excelMapdbs[i].IsFixed)136
{137
fixedRange = ws.get_Range(excelMapdbs[i].ExcelRangeName.Trim().ToUpper(),this._objOpt);138
dr[excelMapdbs[i].RowName] = ConverData(dr.Table.Columns[excelMapdbs[i].RowName].DataType,fixedRange.Value2);139
}140
else141
{142
dr[excelMapdbs[i].RowName] = ConverData(dr.Table.Columns[excelMapdbs[i].RowName].DataType,143
firstRange.get_Offset(_objOpt,excelMapdbs[i].OffYSetStartRange).Value2);144

145
#if DEBUG146
object Checkvalue1 = firstRange.get_Offset(_objOpt,excelMapdbs[i].OffYSetStartRange).Value2;147
#endif148
}149
}150
catch(System.Exception ex)151
{152
throw new Exception( 153
String.Format("<font color=red><b>导入数据失败</b></font><br/>附件编号:<b>{0}</b><br/>错误位置:X={1};Y(相对于开始格)={2};对应RowName:{3}<br/>details:<hr size=1/>{4}",154
this._identity,155
x,156
excelMapdbs[i].OffYSetStartRange,157
excelMapdbs[i].RowName,158
ex.Message));159

160

161
162
}163
}164
165

166
//myTable.Rows.Add(dr);167
dr["SummaryID"] = this._identity;168
ImportDataRow(dr);169

170

171
x++;172
firstRange = firstRange.get_Offset(1,_objOpt);173
#if DEBUG174
object Checkvalue2 = firstRange.Value2;175
#endif176
177

178
}179
return myTable;180
181

182
}183

184
public virtual void ImportDataRow(DataRow row)185
{186
BaseDAL b = new BaseDAL();187
b.ConfigTable(row.Table.TableName,"ID");188
b.Add(row);189
}190

191
ConverData 217

218

219

220
}
至此Excel导入核心的介绍就完毕了,
抛开代码不说,解决问题的方法还是很简单。
1. 描述Excel的数据对应关系
2. 根据对应关系,进行数据转换。
解决这种问题的根本是要有良好的抽象能力,将实际事务转换为一些可以用代码描述的对象。
呵呵。。。
另外补充的是这种方式也可以用以导出Excel, 由您自由想像了。

浙公网安备 33010602011771号