ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

将dataset中的数据导出至Excel中而不需要安装MS Excel的方法(含UNICODE支持)

2022-04-25 13:33:18  阅读:258  来源: 互联网

标签:begin end TDS2Excel Excel dataset FDataSet UNICODE FDbGrid procedure


偶尔做界面程序,需要一个导出Excel,而在客户端又不用安装MS Excel的方法,总结如下。
测试了两种方法,第一种方法如下(此方法支持UNICODE不存在问题):

参考:http://www.swissdelphicenter.ch/torry/showcode.php?id=1427

procedure DBGridToExcelADO(Query: TDataSet; FileName: string; SheetName: string);
var
  cat: _Catalog;
  tbl: _Table;
  col: _Column;
  i: integer;
  ADOConnection: TADOConnection;
  ADOQuery: TADOQuery;
begin
  if FileExists(FileName) then  // It's better to delete the file first, or there may be a "external table is not in the expected format" error. by genispan
      DeleteFile(FileName);
  //WorkBook creation (database)
  cat := CoCatalog.Create;
  //cat._Set_ActiveConnection
  cat.Set_ActiveConnection('Provider=Microsoft.Jet.OLEDB.4.0; Data Source=' + FileName + ';Extended Properties=Excel 8.0');
  //WorkSheet creation (table)
  tbl := CoTable.Create;
  tbl.Set_Name(SheetName);
    //Columns creation (fields)
  Query.First;
  with Query.Fields do
    begin
      for i := 0 to Count - 1 do
      begin
          col := nil;
          col := CoColumn.Create;
          with col do
            begin
              Set_Name(Query.Fields[i].FieldName);
              Set_Type_(adVarWChar);
            end;
          //add column to table
          tbl.Columns.Append(col, adVarWChar, 20);
      end;
    end;
  //add table to database
  cat.Tables.Append(tbl);
 
  col := nil;
  tbl := nil;
  cat := nil;
 
  ADOConnection := TADOConnection.Create(nil);
  ADOConnection.LoginPrompt := False;
  ADOConnection.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0; Data Source=' + FileName + ';Extended Properties=Excel 8.0';
  ADOQuery := TADOQuery.Create(nil);
  ADOQuery.Connection := ADOConnection;
  ADOQuery.SQL.Text := 'Select * from [' + SheetName + '$]';
  ADOQuery.Open;
  try
  with Query do
    begin
      First;
      while not Eof do
        begin
          ADOQuery.Append;
          with Query.Fields do
            begin
              ADOQuery.Edit;
              for i := 0 to Count - 1 do
                  ADOQuery.FieldByName(Query.Fields[i].FieldName).AsString := FieldByName(Query.Fields[i].FieldName).AsString;
              ADOQuery.Post;
            end;
          Next;
        end;
    end;
 
  finally
      ADOQuery.Close;
      ADOConnection.Close;
      ADOQuery.Free;
      ADOConnection.Free;
  end;
end;

第二种方法,此方法效率更高,但导出UNICODE字符串存在问题,如有高手看到可留言帮助解决下,以下为整理好了的pas单元源码:

unit uExcel;
 
interface
 
Uses
    DB, Classes, Dialogs,DBGrids,Controls;
var
    CXlsBof: array[0..5] of Word = ($809, 8, 0, $10, 0, 0);
    //OPCode, size, codepage
    CXlsCodePage: array[0..2] of Word = ($0042, $0002, $04B0);
    CXlsEof: array[0..1] of Word = ($0A, 00);
    CXlsLabel: array[0..5] of Word = ($204, 0, 0, 0, 0, 0);
    CXlsNumber: array[0..4] of Word = ($203, 14, 0, 0, 0);
    CXlsRk: array[0..4] of Word = ($27E, 10, 0, 0, 0);
    CXlsBlank: array[0..4] of Word = ($201, 6, 0, 0, $17);
 
 
Type
TDS2Excel = Class(TObject)
Private
  FCol: word;
  FRow: word;
  FDataSet: TDataSet;
  FDbGrid  :TDbGrid;
  Stream: TStream;
  FWillWriteHead: boolean;
  FBookMark: TBookmark;
  procedure IncColRow;
  procedure WriteBlankCell;
  procedure WriteFloatCell(const AValue: Double);
  procedure WriteIntegerCell(const AValue: Integer);
  procedure WriteStringCell(const AValue: string);
  procedure WritePrefix;
  procedure WriteSuffix;
  procedure WriteTitle;
  procedure WriteDataCell;
 
  procedure Save2Stream(aStream: TStream);
Public
  procedure Save2File(FileName: string; WillWriteHead: Boolean);
  procedure Save2Files(WillWriteHead: Boolean);
  Constructor Create(aDataSet: TDataSet;aDBGrid:TDBGrid);
end;
 
implementation
 
uses SysUtils;
 
Constructor TDS2Excel.Create(aDataSet: TDataSet;aDBGrid:TDBGrid);
begin
    inherited Create;
    FDataSet := aDataSet;
    FDbGrid  :=aDbGrid;
end;
 
 
procedure TDS2Excel.IncColRow;
begin
if FDbGrid <>nil then
begin
    if FCol = FDbGrid.Columns.Count - 1 then
    begin
      Inc(FRow);
      FCol :=0;
    end
    else
      Inc(FCol);
end else
begin
    if FCol = FDataSet.FieldCount - 1 then
    begin
      Inc(FRow);
      FCol :=0;
    end
    else
      Inc(FCol);
end;
end;
 
procedure TDS2Excel.WriteBlankCell;
begin
    CXlsBlank[2] := FRow;
    CXlsBlank[3] := FCol;
    Stream.WriteBuffer(CXlsBlank, SizeOf(CXlsBlank));
    IncColRow;
end;
 
procedure TDS2Excel.WriteFloatCell(const AValue: Double);
begin
    CXlsNumber[2] := FRow;
    CXlsNumber[3] := FCol;
    Stream.WriteBuffer(CXlsNumber, SizeOf(CXlsNumber));
    Stream.WriteBuffer(AValue, 8);
    IncColRow;
end;
 
procedure TDS2Excel.WriteIntegerCell(const AValue: Integer);
var
    V: Integer;
begin
    CXlsRk[2] := FRow;
    CXlsRk[3] := FCol;
    Stream.WriteBuffer(CXlsRk, SizeOf(CXlsRk));
    V := (AValue shl 2) or 2;
    Stream.WriteBuffer(V, 4);
    IncColRow;
end;
 
procedure TDS2Excel.WriteStringCell(const AValue: string);
var
    L: Word;
     _str : AnsiString;
begin
    _str := AnsiString(AValue);  // in delphi XE, there will be error for unicode, fix me !!!!!!!!!!!  --by genispan
    L := Length(_str);
    CXlsLabel[1] := 8 + L;
    CXlsLabel[2] := FRow;
    CXlsLabel[3] := FCol;
    CXlsLabel[5] := L;
    Stream.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel));
    Stream.WriteBuffer(Pointer(_str)^, L);
    IncColRow;
end;
 
procedure TDS2Excel.WritePrefix;
begin
  Stream.WriteBuffer(CXlsBof, SizeOf(CXlsBof));
  Stream.WriteBuffer(cxlscodepage, SizeOf(cxlscodepage));
end;
 
procedure TDS2Excel.WriteSuffix;
begin
  Stream.WriteBuffer(CXlsEof, SizeOf(CXlsEof));
end;
 
procedure TDS2Excel.WriteTitle;
var
   n: word;
begin
    if FDbGrid <> nil then
    for n := 0 to FDBGrid.Columns.Count - 1 do
      WriteStringCell(FDBGrid.Columns[n].Title.Caption)
    else
    for n := 0 to FDataSet.FieldCount - 1 do
      WriteStringCell(FDataSet.Fields[n].FieldName);
end;
 
procedure TDS2Excel.WriteDataCell;
var
  n: word;
begin
  WritePrefix;
  if FWillWriteHead then WriteTitle;
  FDataSet.DisableControls;
  FBookMark := FDataSet.GetBookmark;
  FDataSet.First;
 
  if FDbGrid=nil then
  begin
    while not FDataSet.Eof do
    begin
    for n := 0 to FDataSet.FieldCount - 1 do
    begin
      try
      if FDataSet.Fields[n].IsNull then
        WriteBlankCell
      else begin
        case FDataSet.Fields[n].DataType of
          ftSmallint, ftInteger, ftWord, ftAutoInc, ftBytes:
              WriteIntegerCell(FDataSet.Fields[n].AsInteger);
          ftFloat, ftCurrency, ftBCD:
              WriteFloatCell(FDataSet.Fields[n].AsFloat);
          ftTypedBinary:
        else
          WriteStringCell(FDataSet.Fields[n].AsString);
        end;
      end;
      except
        WriteBlankCell;
      end;
    end;
        FDataSet.Next;
    end;
  end
  else
  begin
    while not FDbGrid.DataSource.DataSet.Eof do
    begin
      for n := 0 to FDbGrid.Columns.Count - 1 do
      begin
        if FDbGrid.Columns[n].Field.IsNull then
          WriteBlankCell
        else begin
          case FDbGrid.Columns[n].Field.DataType of
            ftSmallint, ftInteger, ftWord, ftAutoInc, ftBytes:
                WriteIntegerCell(FDbGrid.Columns[n].Field.AsInteger);
            ftFloat, ftCurrency, ftBCD:
                WriteFloatCell(FDbGrid.Columns[n].Field.AsFloat);
          else
            WriteStringCell(FDbGrid.Columns[n].Field.AsString);
          end;
        end;
      end;
      FDbGrid.DataSource.DataSet.Next
    end;
  end;
 
  WriteSuffix;
  if FDataSet.BookmarkValid(FBookMark) then FDataSet.GotoBookmark(FBookMark);
  FDataSet.EnableControls;
end;
 
procedure TDS2Excel.Save2Stream(aStream: TStream);
begin
    FCol := 0;
    FRow := 0;
    Stream := aStream;
    WriteDataCell;
end;
 
procedure TDS2Excel.Save2File(FileName: string; WillWriteHead: Boolean);
var
    aFileStream: TFileStream;
begin
    FWillWriteHead := WillWriteHead;
    if FileExists(FileName) then DeleteFile(FileName);
    aFileStream := TFileStream.Create(FileName, fmCreate);
    Try
      Save2Stream(aFileStream);
    Finally
      aFileStream.Free;
    end;
end;
 
procedure TDS2Excel.Save2FileS(WillWriteHead: Boolean);
var
    SaveDialog11: TSaveDialog;
begin
    SaveDialog11 := TSaveDialog.Create(nil);
    Try
      SaveDialog11.Filter := 'Excel|*.xls';
      SaveDialog11.InitialDir := 'C:\';
      SaveDialog11.FileName:='*.xls';
      if not SaveDialog11.Execute then exit;
      if FileExists(SaveDialog11.FileName) then DeleteFile(SaveDialog11.FileName);
      Save2File(SaveDialog11.FileName, WillWriteHead);
    Finally
      SaveDialog11.Free;
    end;
end;
 
end.

 

标签:begin,end,TDS2Excel,Excel,dataset,FDataSet,UNICODE,FDbGrid,procedure
来源: https://www.cnblogs.com/jijm123/p/16189861.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有