⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qexport4dbf.pas

📁 Advanced.Export.Component.v4.01.rar,delphi 第三方控件
💻 PAS
字号:
unit QExport4DBF;

{$I VerCtrl.inc}

interface

uses QExport4, Classes, SysUtils, QExport4IniFiles;

const
  dBaseIII = $03;
  dBaseIIIMemo = $83;
  dBaseIVMemo = $8B;
  dBaseIVSQL = $63;
  FoxPro = $05;
  FoxProMemo = $F5;

  dftString  = 'C';  // char (symbol(s))
  dftBoolean = 'L';  // boolean
  dftNumber  = 'N';  // number
  dftDate    = 'D';  // date
  dftMemo    = 'M';  // memo
  dftFloat   = 'F';  // float -- not in DBaseIII

  MAX_FIELD_NAME_LEN = 10;

type

  TFieldName = array[1..MAX_FIELD_NAME_LEN] of Char;

  TDBFHeader = packed record { *** First record ***  L=32 }
   {+0} DBType,
   {+1} Year,
   {+2} Month,
   {+3} Day: Byte;
   {+4} RecCount: LongInt;
   {+8} HeaderSize: Word;
   {+10} RecordSize: Longint;
   {+14} FDelayTrans: Byte;
   {+15} Reserve2: array[1..13] of Byte;
   {+28} FlagMDX: Byte;
   {+29} Reserve3: array[1..3] of Byte;
  end;

  PDBFFieldDescriptor = ^TDBFFieldDescriptor;
  TDBFFieldDescriptor = packed record { *** Field Descriptor *** L= 32 }
    {+0}  FieldName: TFieldName;
    {+10} FieldEnd: Char;
    {+11} FieldType: Char;
    {+12} FieldDisp: LongInt;
    {+16} FieldLen,
    {+17} FieldDec: Byte;
    {+18} A1: array[1..13] of Byte;
    {+31} FlagTagMDX: Byte;
  end;

  //TMemoType = (mtNone, mtDBT, mtFPT);
  TQExport4DBF = class;

  TQDBFWriter = class(TQExportWriter)
  private
    DBFHeader: TDBFHeader;
    DList: TList;
    {$IFDEF QE_UNICODE}
    FExportCharsetType: TQExportCharsetType;
    {$ENDIF}
    MemoStream: TFileStream;
    MemoRecord: PByteArray;
    NextMemoRecord: integer;

    function GetDBFExport: TQExport4DBF;
  protected
    property DBFExport: TQExport4DBF read GetDBFExport;
  public
    constructor Create(AOwner: TQExport4; AStream: TStream); override;
    destructor Destroy; override;
    procedure AddFieldDef(Descriptor: PDBFFieldDescriptor);
    procedure CreateDBF;
    procedure DestroyDBF;
    procedure WriteData(Num: integer; const Data: string);
    function WriteMemo(Index: integer): integer;
    {$IFDEF QE_UNICODE}
    property ExportCharsetType: TQExportCharsetType read FExportCharsetType write
        FExportCharsetType;
    {$ENDIF}
  end;

  TQExport4DBF = class(TQExport4Text)
  private
    FColumnsPrecision: TStrings;
    FOldDecimalSeparator: char;
    FDefaultFloatSize: integer;
    FDefaultFloatDecimal: integer;
    FExportTimeAsStr: Boolean;
    function GetMemoFileName: string;
    function GetNullValue: string;
    procedure SetNullValue(const Value: string);
    procedure SetColumnsPrecision(Value: TStrings);
    procedure GetColumnSizeDecimal(const ColumnName: string; var Size,
      Decimal: integer);
  protected
    function GetWriterClass: TQExportWriterClass; override;
    function GetWriter: TQDBFWriter;

    procedure BeginExport; override;
    procedure EndExport; override;
    procedure BeforeExport; override;
    procedure AfterExport; override;

    procedure WriteDataRow; override;
    procedure SaveProperties(IniFile: TQIniFile); override;
    procedure LoadProperties(IniFile: TQIniFile); override;

    property MemoFileName: string read GetMemoFileName;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Captions;
    property ColumnsLength;
    property ColumnsPrecision: TStrings read FColumnsPrecision
      write SetColumnsPrecision;
    property DefaultFloatSize: integer read FDefaultFloatSize
      write FDefaultFloatSize default 15;
    property DefaultFloatDecimal: integer read FDefaultFloatDecimal
      write FDefaultFloatDecimal default 4;
    property ExportTimeAsStr: Boolean read FExportTimeAsStr write FExportTimeAsStr;
    property NullValue: string read GetNullValue write SetNullValue;
  end;

  TShortFieldNameGenerator = class
  private
    FFieldNames: TStringList;
    function GetNumberString(const AValue: Integer): string;
    function IncNumberString(const AValue: string): string;
  public
    constructor Create;
    destructor Destroy; override;
    function GetShortFieldName(AFieldName: string): string;
  end;

implementation

uses QExport4Common, DB, QExport4Types{$IFDEF VCL9}, Windows{$ENDIF}, Math;

{ TQDBFWriter }

procedure TQDBFWriter.AddFieldDef(Descriptor: PDBFFieldDescriptor);
begin
  DList.Add(Descriptor);
end;

constructor TQDBFWriter.Create(AOwner: TQExport4; AStream: TStream);
begin
  inherited;
  DList := TList.Create;
end;

procedure TQDBFWriter.CreateDBF;
var
  B: Byte;
  I: Integer;
  Y, M, D : Word;
begin
  FillChar(DBFHeader, 32, #0);
  DecodeDate(Date, Y, M, D);
  with DBFHeader do
  begin
    if (Owner as TQExport4DBF).Columns.ContainsBLOB and
       (Stream is TFileStream) then
    begin
      DBType := dBaseIIIMemo;
      MemoStream := TFileStream.Create((Owner as TQExport4DBF).MemoFileName, fmCreate);
      GetMem(MemoRecord, 512);
      FillChar(MemoRecord^, 512, #0);
      MemoStream.WriteBuffer(MemoRecord^, 512);
      NextMemoRecord := 1;
    end
    else DBType := dBaseIII;

    Year := Y - 2000;
    Month := M;
    Day := D;
    HeaderSize := (DList.Count + 1) * 32 + 1;
    RecordSize := 1;
    for I := 0 to DList.Count - 1 do
      RecordSize := RecordSize + PDBFFieldDescriptor(DList[I])^.FieldLen;
  end;
  Stream.WriteBuffer(DBFHeader, SizeOf(DBFHeader));
  for I := 0 to DList.Count - 1 do
    Stream.WriteBuffer(PDBFFieldDescriptor(DList[I])^, 32);
  B := $0D; // End of DBF Header
  Stream.WriteBuffer(B, SizeOf(B));
end;

destructor TQDBFWriter.Destroy;
var
  i: Integer;
begin
  for i := 0 to DList.Count - 1 do
    if Assigned(DList.Items[i]) then
      Dispose(PDBFFieldDescriptor(DList.Items[i]));
  DList.Free;
  inherited;
end;

procedure TQDBFWriter.DestroyDBF;
begin
  if Assigned(MemoStream) then begin
    MemoStream.Seek(0, soFromBeginning);
    MemoStream.Write(NextMemoRecord, SizeOf(Integer));
    MemoStream.Free;
  end;
end;

function TQDBFWriter.GetDBFExport: TQExport4DBF;
begin
  Result := Owner as TQExport4DBF;
end;

procedure TQDBFWriter.WriteData(Num: integer; const Data: string);

  {$IFDEF QE_UNICODE}
  procedure WriteUsingCharset(WS: WideString);
  var
    s: string;
    UCS4: UCS4String;
  begin
    if not Assigned(Owner) then
      Exit;
    if WS = EmptyStr then
      Exit;

    case ExportCharsetType of
      ectLocalANSI, ectLocalOEM, ectLocalMAC:
        begin
          s := WideStringToString(WS, Integer(ExportCharsetType));
          if length(s) > length(ws) then
            SetLength(s, Length(ws));
          Stream.WriteBuffer(s[1], Length(s));
        end;
      ectUTF8:
        begin
          s := UTF8Encode(WS);
          if length(s) > length(ws) then
            SetLength(s, Length(ws));
          Stream.WriteBuffer(s[1], Length(s));
        end;
      ectUTF16:
        begin
          Stream.WriteBuffer(WS[1], Length(WS) * SizeOf(WideChar));
        end;
      ectUTF32:
        begin
          UCS4 := WideStringToUCS4String(WS);
          Stream.WriteBuffer(UCS4[1], Length(UCS4) * SizeOf(LongWord));
        end;
    end;
  end;
  {$ENDIF}

const
  NewRecordMarker: Byte = $20;
  STrue  = 'TRUE';
  SFalse = 'FALSE';
  SDBFTrue  = 'T';
  SDBFFalse = 'F';
var
  CurPos, RCount: integer;
  _Data: string;
  DD: TDateTime;
begin
  SetLength(_Data, PDBFFieldDescriptor(DList[Num])^.FieldLen);
  FillChar(_Data[1], Length(_Data), ' ');
  if Data <> EmptyStr then begin
    case PDBFFieldDescriptor(DList[Num])^.FieldType of
      dftString:
          if Length(Data) > 254 // !!!
            then Move(Data[1], _Data[1], 254) // !!!
            else Move(Data[1], _Data[1], Length(Data));
      dftNumber:
         begin
           Move(Data[1], _Data[Max(Length(_Data) - Length(Data) + 1, 1)], Length(Data));
         end;
      dftDate: begin
          DD := StrToDateTime(Data);
          _Data := FormatDateTime('yyyymmdd', DD);
         if _Data = EmptyStr then begin
           SetLength(_Data, 8);
           FillChar(_Data[1], 8, ' ');
         end;
      end;
      dftBoolean: begin
        if Pos(STrue, UpperCase(Data)) > 0 then
          _Data[1] := SDBFTrue
        else
        if Pos(SFalse, UpperCase(Data)) > 0 then
          _Data[1] := SDBFFalse
        else
          _Data[1] := ' ';
      end;
    end;
  end;
  if Num = 0 then begin
      Stream.WriteBuffer(NewRecordMarker, 1); // it's new record
      // update record count
      CurPos := Stream.Position; // save current position
      Stream.Position := 4;
      Stream.ReadBuffer(RCount, 4);
      Inc(RCount);
      Stream.Position := 4;
      Stream.WriteBuffer(RCount, 4);
      Stream.Position := CurPos; // restore current position
  end;
  {$IFDEF QE_UNICODE}
  WriteUsingCharset(_Data); //alex c - 桉镱朦珞弪

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -