一種加快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;
  end
end

上述方法我測試下來的結果是比二進制導出還要快很多。我測試導6W行27列的數據,二進制需要5分鐘,上述方法需要1分鐘左右。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章