Delphi數據庫數據用文件流方式快速寫入Excel文件


 

在開發數據庫應用程序中,經常要將類型相同的數據導出來,放到Excel文件中,利用Excel強大的編輯功能,對數據作進一步的加工處理。這有許多的方法,我們可以使用OLE技術,在Delphi中創建一個自動化對象,通過該對象來傳送數據。也可以使用ADO,通過與Excel數據存儲建立連接,使用ADO這種獨立於數據庫后端的技術來導出數據集的數據。

可這兩種技術都有一個共同的缺點,那就是慢,數據量少還好,用戶不會有太多的感覺,可一旦數據量大,比如,超過1千條,速度就讓人難以忍受了,那么有沒有更好的辦法,既可以快速地導出數據,又不用安裝附加的軟件。也許好多人都想到了剪貼板的方式,這種方式速度是快,可也有不好的一面,那就是數據量大占用內存也大,並且在Excel中調用PASTE方法時,需要鎖定輸入,這使用起來,就有點不方便了

這里我為大家介始一種比較好的方法,使用文件流的方式,通過TfileStream直接寫入Excel文件。我寫了一個函數,通過它可將數據集中的數據直接導入到Excel文件中。我測試了一下,1M的數據,不到十秒就完成了。附源程序。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,DB, ADODB, Grids, DBGrids, StdCtrls;

type  
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    ADOTable1: TADOTable;
    DataSource1: TDataSource;
    ADOConnection1: TADOConnection;
    ADOTable1record_id: TIntegerField;
    ADOTable1action_id: TIntegerField;
    ADOTable1action_name: TStringField;
    ADOTable1net_name: TStringField;
    ADOTable1deal_no: TStringField;
    ADOTable1name: TStringField;
    ADOTable1getno_date: TDateTimeField;
    ADOTable1window_no: TIntegerField;
    ADOTable1staff_id: TStringField;
    ADOTable1staff_name: TStringField;
    ADOTable1deal_date: TDateTimeField;
    ADOTable1deal_type: TStringField;
    ADOTable1finish_date: TDateTimeField;
    ADOTable1state: TStringField;
    ADOTable1appraise: TStringField;
    ADOTable1appraised_flag: TBooleanField;
    ADOTable1cancel_led_time: TDateTimeField;
    ADOTable1wait_time: TBCDField;
    ADOTable1wait_time2: TStringField;
    ADOTable1accept_time: TBCDField;
    ADOTable1accept_time2: TStringField;
    ADOTable1getnumber_addr: TIntegerField;
    ADOTable1cust_level: TIntegerField;
    ADOTable1cust_level_name: TStringField;
    ADOTable1cust_level_name_remark: TStringField;
    ADOTable1operation_sum: TIntegerField;
    Button1: TButton;
    SaveDialog1: TSaveDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  arXlsBegin: array[0..5] of Word = ($809, 8, 0, $10, 0, 0);
  arXlsEnd: array[0..1] of Word = ($0A, 00);

  arXlsString: array[0..5] of Word = ($204, 0, 0, 0, 0, 0);
  arXlsNumber: array[0..4] of Word = ($203, 14, 0, 0, 0);

  arXlsInteger: array[0..4] of Word = ($27E, 10, 0, 0, 0);

  arXlsBlank: array[0..4] of Word = ($201, 6, 0, 0, $17);
implementation

{$R *.dfm}

Procedure ExportExcelFile(FileName: string; bWriteTitle: Boolean; aDataSet: TDataSet);
var
  i, j: integer;
  Col, row: word;
  ABookMark: TBookMark;
  aFileStream: TFileStream;
  procedure incColRow; //增加行列號
  begin
    if Col = ADataSet.FieldCount - 1 then
    begin
      Inc(Row);
      Col :=0;
    end
    else
     Inc(Col);
  end;
  procedure WriteStringCell(AValue: string);//寫字符串數據
  var
    L: Word;
  begin
    L := Length(AValue);
    arXlsString[1] := 8 + L;
    arXlsString[2] := Row;
    arXlsString[3] := Col;
    arXlsString[5] := L;
    aFileStream.WriteBuffer(arXlsString, SizeOf(arXlsString));
    aFileStream.WriteBuffer(Pointer(AValue)^, L);
    IncColRow;
  end;
  procedure WriteIntegerCell(AValue: integer);//寫整數
  var
    V: Integer;
  begin
    arXlsInteger[2] := Row;
    arXlsInteger[3] := Col;
    aFileStream.WriteBuffer(arXlsInteger, SizeOf(arXlsInteger));
    V := (AValue shl 2) or 2;
    aFileStream.WriteBuffer(V, 4);
    IncColRow;
  end;
  procedure WriteFloatCell(AValue: double);//寫浮點數
  begin
    arXlsNumber[2] := Row;
    arXlsNumber[3] := Col;
    aFileStream.WriteBuffer(arXlsNumber, SizeOf(arXlsNumber));
    aFileStream.WriteBuffer(AValue, 8);
    IncColRow;
  end;
begin
  if FileExists(FileName) then
    DeleteFile(FileName); //文件存在,先刪除
  aFileStream := TFileStream.Create(FileName, fmCreate);
  Try
    //寫文件頭
    aFileStream.WriteBuffer(arXlsBegin, SizeOf(arXlsBegin));
    //寫列頭
    Col := 0; Row := 0;
    if bWriteTitle then
    begin
      for i := 0 to aDataSet.FieldCount - 1 do
        WriteStringCell(aDataSet.Fields[i].FieldName);
    end;
    //寫數據集中的數據
    aDataSet.DisableControls;
    ABookMark := aDataSet.GetBookmark;
    aDataSet.First;
    while not aDataSet.Eof do
    begin
      for i := 0 to aDataSet.FieldCount - 1 do
        case ADataSet.Fields[i].DataType of
          ftSmallint, ftInteger, ftWord, ftAutoInc, ftBytes:
          WriteIntegerCell(aDataSet.Fields[i].AsInteger);
          ftFloat, ftCurrency, ftBCD:
          WriteFloatCell(aDataSet.Fields[i].AsFloat)
        else
          WriteStringCell(aDataSet.Fields[i].AsString);
        end;
      aDataSet.Next;
    end;
    //寫文件尾
    AFileStream.WriteBuffer(arXlsEnd, SizeOf(arXlsEnd));
    if ADataSet.BookmarkValid(ABookMark) then
      aDataSet.GotoBookmark(ABookMark);
  finally
    AFileStream.Free;
    ADataSet.EnableControls;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if SaveDialog1.Execute then
  begin
    ExportExcelFile(SaveDialog1.FileName,True,DBGrid1.DataSource.DataSet);
  end;  
end;

end.

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM