一种加快OLE导出Excel的方法
相信使用过OLE导入导出Excel的人都知道,微软出的这个东西真是慢到极点,慢到你想砸电脑。
我们公司以前Excel导出大概2w行,30多列,耗时20多分钟。想屎的心都有。。。。
现在有一些快速导出Excel的方法,一般都是使用二进制导出,就是不依靠Excel软件,利用二进制流直接填写数据,比如DBGridEh的SaveDBGridEhToExportFile方法,这种方法确实非常快,但是有一个弊端,就是二进制导出的文件如果系统后续需要导入这个文件的话解析就会出错,所以要想导入只有重新使用Excel另存一下,使格式标准。
那么,有没有一种即使用OLE,速度又和二进制差不多甚至更快的方法?
答案当然是有的,程序猿都知道算法要考虑时间复杂度和空间复杂度。要想加快程序的运行一个很常用的方法就是用空间来换时间,前提是你内存足够,当然现在内存白菜价。。。
废话讲了一堆,下面就讲讲这种方法,我讲的是基于Delphi 的基础的,语言都是想通的。。其实很简单。
首先假设我们的数据是在DBGrid里面要导出到Excel。那么我们可以先把数据以一定数据格式全部拿到内存中,然后复制到剪贴板,最后粘贴到Excel中不就可以不用一个个Cell去填写了。
Excel复制粘贴的数据格式是:A tab B tab C tab D.....
……
X tab Y……
tab是制表符,都懂得哈。
示例源码:
procedure ExportToXLS(Sender: TObject);var fileName: string; i,j,m:Integer; BM:TBookmark; ExcelApp: Variant; sCopyStrings:TStrings;//用来存放导出数据 sline:string;begin try BM:=nil; SaveDialog.Filter:='Excel 文件(*.xls)|*.xls|文本文件(*.txt)|*.txt'; if (not SaveDialog.Execute) then exit; fileName := Trim(SaveDialog.FileName); try ExcelApp := CreateOleObject('Excel.Application'); ExcelApp.DisplayAlerts := False; ExcelApp.Workbooks.Add; except ShowMessage('没有安装Excel!'); Exit; end; while ExcelApp.WorkSheets.Count>1 do begin ExcelApp.WorkSheets[1].Delete; end; sCopyStrings:=TStringList.Create(); //TStrings是抽象类,不能实例化,用从TString继承来的TStringList sCopyStrings.Clear; tmpQuery.DisableControls; BM:=tmpQuery.GetBookmark; sline:=''; for j:=0 to DBGrid.Columns.Count-1 do begin sline:=sline+DBGrid.Columns[j].Title.Caption+#9; //数据格式,#9就是tab 这是表头 end; sCopyStrings.Add(sline); m:=0; tmpQuery.First; while not tmpQuery.Eof do begin sline:=''; for j:=0 to dbRisk.Columns.Count-1 do begin sline := sline + dbRisk.Columns[j].Field.AsString + #9; Inc(m);//m可以用来统计导出进度,这里没实现 Application.ProcessMessages;//处理消息,防止界面假死 end; sCopyStrings.Add(sline); tmpQuery.Next; end; Clipboard.AsText:=sCopyStrings.Text;//复制到剪贴板,这里的Clipboard是TClipboard的一个对象,Delphi已经给你实例化好了,在uses里加clipbrd try ExcelApp.Workbooks[1].Worksheets[1].Range['A:ZZ'].Select ; ExcelApp.Selection.NumberFormat:='@'; //这两句是将Excel的从A到ZZ列格式设为文本,如果不改的话,如果是00123样子的数据导入话,到Excel中就只剩123了。 ExcelApp.Workbooks[1].WorkSheets[1].Cells[1,1].Select;//加上这句是为了保证执行下面Paste时不会出现Paste方法无效的错误。 ExcelApp.Workbooks[1].WorkSheets[1].Paste; ExcelApp.workbooks[1].SaveAs(fileName); finally Clipboard.Clear; Clipboard.Close; ExcelApp.WorkBooks.Close; ExcelApp.Quit; tmpQuery.GotoBookmark(BM); tmpQuery.EnableControls; if Assigned(sCopyStrings) then FreeAndNil(sCopyStrings); end; endend