delphi 通用的将Excel导入数据集的方法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/baronyang/article/details/7048563

开发中经常有需要将Excel导入数据集的需要,但每张Excel的栏位都会不同,常规的做法有两种:

一、针对每一张Excel的栏位与数据集栏位位置在程序中写好,一一对应导入

二、针对每一张Excel的栏位与数据集栏位配置好应用参数

这两种方法都比较麻烦,很不灵活,所以我写了一个比较通用的方法,只要符合以下条件就可以直接使用:

 1、Excel第一行是栏位标题,第二行开始是数据

 2、应用程序数据集显示控件如(dbgrid,dxdbgrid等)名称与Excel首行标题名一致(顺序可以不同,数量也可以不同,如Excel的栏位:工号,姓名,年龄;显示控件栏位:姓名,工号,年龄,创建时间;这也是可以的)

以下为delphi 代码:

 
 
  1. procedure ExportExcelToCDS(mygrid: TdxDBGrid; filename: string);
  2. var
  3. i,j,row,col,ValidFNCount:integer;
  4. MyExcel,Sheet:Variant;
  5. str1,Prompt,ts: string;
  6. fieldnames: array of string;
  7. fieldList: array of string;
  8. ColIndex: array of Integer; //Excel列序号
  9. tmpcds:TDataSet;
  10. tmpds:TDataSource;
  11. CelValue: string;
  12. //搜索Excel的标题是否有对应到数据表中的字段
  13. procedure SetFieldList;
  14. var
  15. t,t2,js:Integer;
  16. str1,str2: string;
  17. begin
  18. //搜索Excel中的有效字段
  19. for t:= 1 to col do
  20. begin
  21. str1:=StringReplace(Sheet.Cells[ 1,t].Text, ' ', '',[rfReplaceAll]);
  22. for t2:= 0 to mygrid.ColumnCount- 1 do
  23. begin
  24. str2:=StringReplace(mygrid.Columns[t2].Caption, ' ', '',[rfReplaceAll]);
  25. if str1=str2 then
  26. begin
  27. ValidFNCount:=ValidFNCount+ 1;
  28. Break;
  29. end;
  30. end;
  31. end;
  32. SetLength(fieldList,ValidFNCount);
  33. SetLength(ColIndex,ValidFNCount);
  34. js:= 0;
  35. for t:= 1 to col do
  36. begin
  37. str1:=StringReplace(Sheet.Cells[ 1,t].Text, ' ', '',[rfReplaceAll]);
  38. for t2:= 0 to mygrid.ColumnCount- 1 do
  39. begin
  40. str2:=StringReplace(mygrid.Columns[t2].Caption, ' ', '',[rfReplaceAll]);
  41. if str1=str2 then
  42. begin
  43. fieldList[js]:=mygrid.Columns[t2].FieldName; //字段
  44. fieldnames[js]:=mygrid.Columns[t2].Caption; //字段显示名称
  45. ColIndex[js]:=t; //Excel列序号1...
  46. js:=js+ 1;
  47. Break;
  48. end;
  49. end;
  50. end;
  51. end;
  52. function CheckField: string;
  53. var
  54. t:Integer;
  55. str1: string;
  56. begin
  57. for t:= 1 to col do
  58. begin
  59. str1:=stringreplace(Sheet.Cells[ 1,t].Text, ' ', '',[rfReplaceAll]);
  60. if str1=fieldnames[i] then
  61. begin
  62. Break;
  63. end;
  64. Result:=str1;
  65. end;
  66. end;
  67. //Excel列名至少有一个与grid中的字段相对应,是否不执行数据追加操作
  68. function CheckFieldArray:Boolean;
  69. var
  70. t,t2:integer;
  71. begin
  72. t2:= 0;
  73. for t:= 0 to col- 1 do
  74. begin
  75. if Trim(fieldList[t])<> '' then
  76. begin
  77. t2:= 1;
  78. Break;
  79. end;
  80. end;
  81. if t2= 0 then
  82. Result:=true
  83. else
  84. Result:=False;
  85. end;
  86. begin
  87. if UpperCase(ExtractFileExt(filename))<>uppercase( '.xlsx') then
  88. begin
  89. ExportXLSToCDS(mygrid,filename);
  90. Exit;
  91. End;
  92. //支持Excel2007格式
  93. tmpcds:=mygrid.DataSource.DataSet;
  94. tmpds:=mygrid.DataSource;
  95. try
  96. MyExcel:=CreateOleObject( 'Excel.Application');
  97. except
  98. ts:= '请安装Excel';
  99. MessageDlg(ts,mtWarning,[mbok], 0);
  100. Exit;
  101. end;
  102. tmpcds.DisableControls;
  103. SetLength(fieldnames,mygrid.ColumnCount);
  104. try
  105. for i:= 0 to mygrid.ColumnCount- 1 do
  106. begin
  107. if mygrid.Columns[i].Visible then
  108. fieldnames[i]:=stringreplace(mygrid.Columns[i].Caption, ' ', '',[rfReplaceAll]);
  109. end;
  110. str1:=CheckField;
  111. if str1<> '' then
  112. begin
  113. MessageDlg( 'Excel中的'+str1+ '不正确',mtError,[mbOK], 0);
  114. Exit;
  115. end;
  116. MyExcel.Workbooks.open(filename);
  117. Sheet:=MyExcel.ActiveSheet;
  118. row:=Sheet.UsedRange.Rows.Count; //行数
  119. col:=Sheet.UsedRange.Columns.Count; //列数
  120. if row<= 1 then
  121. begin
  122. Prompt:= 'Excel中至少有一条数据'+ #13+ '第一行是标题,其它行为数据行'+ #13+ '条件不符,操作取消';
  123. MessageDlg(Prompt,mtWarning,[mbOK], 0);
  124. Exit;
  125. end;
  126. if col<= 1 then
  127. begin
  128. Prompt:= 'Excel中至少有一列数据'+ #13+ '条件不符,操作取消';
  129. MessageDlg(Prompt,mtWarning,[mbOK], 0);
  130. Exit;
  131. end;
  132. SetFieldList;
  133. if CheckFieldArray then
  134. begin
  135. Prompt:= 'Excel中第一行中的列名至少有一个与列表中栏位相同'+ #13+ '条件不符,操作取消';
  136. MessageDlg(Prompt,mtWarning,[mbOK], 0);
  137. Exit;
  138. end;
  139. Screen.Cursor:=crHourGlass;
  140. if not tmpcds.Active then
  141. tmpcds.Open;
  142. for i:= 2 to row do
  143. begin
  144. Application.ProcessMessages;
  145. CelValue:=Trim(Sheet.Cells[i, 0].Text);
  146. if (CelValue= '') then Continue;
  147. tmpcds.Append;
  148. for j:= 0 to ValidFNCount- 1 do
  149. begin
  150. Application.ProcessMessages;
  151. CelValue:=Trim(Sheet.Cells[i,ColIndex[j]].Text);
  152. try
  153. //导入的数据文本不可以有公式,否则会出错
  154. if (CelValue<> '') then
  155. begin
  156. case tmpcds.FieldByName(fieldList[j]).DataType of
  157. ftString:
  158. tmpcds.FieldByName(fieldList[j]).AsString:=CelValue;
  159. ftSmallint,ftInteger,ftWord,ftBoolean,ftFloat,ftCurrency,
  160. ftBCD,ftBytes:
  161. tmpcds.FieldByName(fieldList[j]).Value:=StrToFloat(CelValue);
  162. ftDate,ftTime,ftDateTime:
  163. tmpcds.FieldByName(fieldList[j]).AsDateTime:=Sheet.Cells[i,ColIndex[j]].Value;
  164. end;
  165. end;
  166. except
  167. on E:Exception do
  168. begin
  169. MessageDlg(E. Message+ #13+ '写入字段'+fieldList[j]+ '时出错,写入内容:'
  170. +vartostr(CelValue)+ #13+ 'Excel出错行列:'+inttostr(i)+ ','+inttostr(j),mtError,[mbOK], 0);
  171. end;
  172. end;
  173. end;
  174. tmpcds.Post;
  175. end;
  176. finally
  177. tmpcds.EnableControls;
  178. MyExcel.Workbooks.close;
  179. MyExcel.quit;
  180. Sheet:=Unassigned;
  181. MyExcel:=Unassigned;
  182. Screen.Cursor:=crDefault;
  183. MessageDlg( '数据导入完毕',mtInformation,[mbOK], 0);
  184. end;
  185. end;

以上方法通过创建Excel对象导入其数据的,未使用第三方控件,其传入参数dxgrid可以改成您应用程序自已的控件类型,只要其带有datasource.dataset属性即可,比较灵活,但数据量比较大时可能比较慢,所以我做了一下改进,使用第三方控件读取Excel,再执行导入操作,这样速度非常快,以下是我改进的使用TcxSpreadSheet控件读取Excel的方法:


 
 
  1. procedure ExportXLSToCDS(mygrid:TdxDBGrid;filename:string); //将excel导入数据集
  2. var
  3. i,j,row,col,ValidFNCount:integer;
  4. MyExcel:TcxSpreadSheet;
  5. str1,Prompt: string;
  6. fieldnames: array of string;
  7. fieldList: array of string;
  8. ColIndex: array of Integer; //Excel列序号
  9. tmpcds:TDataSet;
  10. tmpds:TDataSource;
  11. CelValue: string;
  12. //搜索Excel的标题是否有对应到数据表中的字段
  13. procedure SetFieldList;
  14. var
  15. t,t2,js:Integer;
  16. str1,str2: string;
  17. begin
  18. //搜索Excel中的有效字段
  19. for t:= 0 to col- 1 do
  20. begin
  21. str1:=StringReplace(MyExcel.Sheet.getcellobject(t, 0).Text, ' ', '',[rfReplaceAll]);
  22. for t2:= 0 to mygrid.ColumnCount- 1 do
  23. begin
  24. str2:=StringReplace(mygrid.Columns[t2].Caption, ' ', '',[rfReplaceAll]);
  25. if str1=str2 then
  26. begin
  27. ValidFNCount:=ValidFNCount+ 1;
  28. Break;
  29. end;
  30. end;
  31. end;
  32. SetLength(fieldList,ValidFNCount);
  33. SetLength(ColIndex,ValidFNCount);
  34. js:= 0;
  35. for t:= 0 to col- 1 do
  36. begin
  37. str1:=StringReplace(MyExcel.Sheet.getcellobject(t, 0).Text, ' ', '',[rfReplaceAll]);
  38. for t2:= 0 to mygrid.ColumnCount- 1 do
  39. begin
  40. str2:=StringReplace(mygrid.Columns[t2].Caption, ' ', '',[rfReplaceAll]);
  41. if str1=str2 then
  42. begin
  43. fieldList[js]:=mygrid.Columns[t2].FieldName; //字段
  44. fieldnames[js]:=mygrid.Columns[t2].Caption; //字段显示名称
  45. ColIndex[js]:=t; //Excel列序号1...
  46. js:=js+ 1;
  47. Break;
  48. end;
  49. end;
  50. end;
  51. end;
  52. function CheckField: string;
  53. var
  54. t:Integer;
  55. str1: string;
  56. begin
  57. for t:= 0 to col- 1 do
  58. begin
  59. str1:=stringreplace(MyExcel.Sheet.getcellobject(t, 0).Text, ' ', '',[rfReplaceAll]);
  60. if str1=fieldnames[i] then
  61. begin
  62. Break;
  63. end;
  64. Result:=str1;
  65. end;
  66. end;
  67. //Excel列名至少有一个与grid中的字段相对应,是否不执行数据追加操作
  68. function CheckFieldArray:Boolean;
  69. var
  70. t,t2:integer;
  71. begin
  72. t2:= 0;
  73. for t:= 0 to col- 1 do
  74. begin
  75. if Trim(fieldList[t])<> '' then
  76. begin
  77. t2:= 1;
  78. Break;
  79. end;
  80. end;
  81. if t2= 0 then
  82. Result:=true
  83. else
  84. Result:=False;
  85. end;
  86. begin
  87. tmpcds:=mygrid.DataSource.DataSet;
  88. tmpds:=mygrid.DataSource;
  89. MyExcel:=TcxSpreadSheet.Create( nil);
  90. tmpcds.DisableControls;
  91. SetLength(fieldnames,mygrid.ColumnCount);
  92. try
  93. for i:= 0 to mygrid.ColumnCount- 1 do
  94. begin
  95. if mygrid.Columns[i].Visible then
  96. fieldnames[i]:=stringreplace(mygrid.Columns[i].Caption, ' ', '',[rfReplaceAll]);
  97. end;
  98. str1:=CheckField;
  99. if str1<> '' then
  100. begin
  101. MessageDlg( 'Excel中的'+str1+ '不正确',mtError,[mbOK], 0);
  102. Exit;
  103. end;
  104. MyExcel.LoadFromFile(filename);
  105. row:=MyExcel.Sheet.ContentRowCount; //行数
  106. col:=MyExcel.Sheet.ContentColCount; //列数
  107. if row<= 1 then
  108. begin
  109. Prompt:= 'Excel中至少有一条数据'+ #13+ '第一行是标题,其它行为数据行'+ #13+ '条件不符,操作取消';
  110. MessageDlg(Prompt,mtWarning,[mbOK], 0);
  111. Exit;
  112. end;
  113. if col<= 1 then
  114. begin
  115. Prompt:= 'Excel中至少有一列数据'+ #13+ '条件不符,操作取消';
  116. MessageDlg(Prompt,mtWarning,[mbOK], 0);
  117. Exit;
  118. end;
  119. SetFieldList;
  120. if CheckFieldArray then
  121. begin
  122. Prompt:= 'Excel中第一行中的列名至少有一个与列表中栏位相同'+ #13+ '条件不符,操作取消';
  123. MessageDlg(Prompt,mtWarning,[mbOK], 0);
  124. Exit;
  125. end;
  126. Screen.Cursor:=crHourGlass;
  127. if not tmpcds.Active then
  128. tmpcds.Open;
  129. for i:= 1 to row- 1 do
  130. begin
  131. Application.ProcessMessages;
  132. CelValue:=Trim(MyExcel.Sheet.getcellobject(ColIndex[ 0],i).DisplayText);
  133. if (CelValue= '') then Continue;
  134. tmpcds.Append;
  135. for j:= 0 to ValidFNCount- 1 do
  136. begin
  137. Application.ProcessMessages;
  138. CelValue:=MyExcel.Sheet.getcellobject(ColIndex[j],i).DisplayText;
  139. try
  140. //导入的数据文本不可以有公式,否则会出错
  141. if VarToStr(CelValue)<> '' then
  142. begin
  143. case tmpcds.FieldByName(fieldList[j]).DataType of
  144. ftString:
  145. tmpcds.FieldByName(fieldList[j]).AsString:=CelValue;
  146. ftSmallint,ftInteger,ftWord,ftBoolean,ftFloat,ftCurrency,
  147. ftBCD,ftBytes:
  148. tmpcds.FieldByName(fieldList[j]).Value:=StrToFloat(CelValue);
  149. ftDate,ftTime,ftDateTime:
  150. tmpcds.FieldByName(fieldList[j]).AsDateTime:=MyExcel.Sheet.getcellobject(ColIndex[j],i).DateTime;
  151. end;
  152. end;
  153. except
  154. on E:Exception do
  155. begin
  156. MessageDlg(E. Message+ #13+ '写入字段'+fieldList[j]+ '时出错,写入内容:'
  157. +vartostr(CelValue)+ #13+ 'Excel出错行列:'+inttostr(i)+ ','+inttostr(j),mtError,[mbOK], 0);
  158. end;
  159. end;
  160. end;
  161. tmpcds.Post;
  162. end;
  163. finally
  164. tmpcds.EnableControls;
  165. Screen.Cursor:=crDefault;
  166. FreeAndNil(MyExcel);
  167. MessageDlg( '数据导入完毕',mtInformation,[mbOK], 0);
  168. end;
  169. end;
注:我使用的TcxSpreadSheet版本比较低,只支持.xls格式.各种开发工具使用以上方法只要将代码稍做改动即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值