.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
/// 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
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对应数据表的关系对象
这个对象还要考虑,它用什么转换器来转换
2 /// ExcelMapDB 的摘要说明。
3 /// Author:King astar
4 /// Date:2005-10-27
5 /// Description:用来描述Excel表对应数据表的关系
6 /// </summary>
7 public class ExcelMapDbRelation
8 {
9 private ExcelMapDB[] _relationItems;
10 [XmlArray("RelationItems")]
11 public ExcelMapDB[] RelationItems
12 {
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 DataTableProviderType
23 {
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 ExcelStartRangeName
36 {
37 get{return _excelStartRangeName;}
38 set{_excelStartRangeName = value;}
39 }
40
41 /// <summary>
42 /// 取得数据提供者对象
43 /// </summary>
44 [XmlIgnore]
45 public IDataTableProvider TableProvider
46 {
47 get
48 {
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 ConvertorType
67 {
68 get{return _convertorType;}
69 set{_convertorType = value;}
70 }
71
72 /// <summary>
73 /// 取得转换器对象
74 /// </summary>
75 [XmlIgnore]
76 public IConvertor DataConvertor
77 {
78 get
79 {
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 constructor
102 }
103
作了这些基础工作后,我考虑可以来写转换器的工作了,这部分工作是核心工作,在这部分数据会从Excel导入到数据库去。
看看接口
2 /// IConvertor 的摘要说明。
3 /// </summary>
4 public interface IConvertor
5 {
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 astar
5 /// Date:2005-10-27
6 /// Description:核心类,将Excel数据导入数据库,是基类,可以继承
7 /// </summary>
8 public class BaseConvertor : IConvertor
9 {
10
11 variable
26
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 try
72 {
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 try
84 {
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(
1241,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 try
134 {
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 else
141 {
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 DEBUG
146 object Checkvalue1 = firstRange.get_Offset(_objOpt,excelMapdbs[i].OffYSetStartRange).Value2;
147#endif
148 }
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 DEBUG
174 object Checkvalue2 = firstRange.Value2;
175#endif
176
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, 由您自由想像了。