繁体   English   中英

如何正确保存和恢复 Delphi 组件的状态?

[英]How can I save and restore the state of a Delphi component properly?

我正在尝试保存组件的状态,然后再恢复它。 我已经制作了一个小班级助手来这样做,但 Delphi 恢复班级的顺序导致了问题。 它正确恢复定界符,然后设置 RecordFormat,后者又将定界符写入分号。 所以我最终得到了错误的值。 你对我如何解决这个问题有什么建议吗? 我喜欢使用类助手的简单性,但如果我以后必须处理它,它会变得复杂。

interface

type
  TFDBatchMoveTextReaderHelper = class helper for TFDBatchMoveTextReader
  private
    function GetState: String;
    procedure SetState( const Value: String );
  published
    property State: String read GetState write SetState;
  end;


implementation

function ComponentToStringProc( Component: TComponent ): string;
var
  BinStream: TMemoryStream;
  StrStream: TStringStream;
  s        : string;
begin
  BinStream := TMemoryStream.Create;
  try
    StrStream := TStringStream.Create( s );
    try
      BinStream.WriteComponent( Component );
      BinStream.Seek( 0, soFromBeginning );
      ObjectBinaryToText( BinStream, StrStream );
      StrStream.Seek( 0, soFromBeginning );
      Result := StrStream.DataString;
    finally
      StrStream.Free;
    end;
  finally
    BinStream.Free
  end;
end;

procedure StrtoComp( Value: string; AComponent: TComponent );
var
  StrStream: TStringStream;
  BinStream: TMemoryStream;
begin
  StrStream := TStringStream.Create( Value );
  try
    BinStream := TMemoryStream.Create;
    try
      ObjectTextToBinary( StrStream, BinStream );
      BinStream.Seek( 0, soFromBeginning );
      BinStream.ReadComponent( AComponent );
    finally
      BinStream.Free;
    end;
  finally
    StrStream.Free;
  end;
end;


{ TFDBatchMoveTextReaderHelper }

function TFDBatchMoveTextReaderHelper.GetState: String;
begin
  Result := ComponentToStringProc( Self );
end;

procedure TFDBatchMoveTextReaderHelper.SetState( const Value: String );
begin
  StrtoComp( Value, Self );
end;

initialization

RegisterClass( TFDBatchMoveTextReader );

end.

这是我的结果(忽略文件名中的差异,我在再次记录状态之前更改了它。这是我遇到问题的 DataDef 值)

Text Compare
Produced: 27/03/2020 07:56:58

Mode:  All
Left file: Clipboard at 27/03/2020 07:54:09     Right file: Clipboard at 27/03/2020 07:54:18
AReaderState from the database = object TextReader: TFDBatchMoveTextReader <> lReader.State after applied to the object = object TextReader: TFDBatchMoveTextReader
  FileName = 'c:\molen\impexp\import\adm_loads_foynes.csv'                      FileName =
                                                                                  'C:\Users\stevesinclair\AppData\Local\Temp\96FFA4BD1C064E77972398' +
                                                                                  '7AD6E15495\adm_loads_foynes.csv'
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
  DataDef.Fields = <                                                       =    DataDef.Fields = <
    item                                                                          item
      FieldName = 'LOAD_ID'                                                         FieldName = 'LOAD_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end                                                                           end
    item                                                                          item
      FieldName = 'SITE_ID'                                                         FieldName = 'SITE_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 5                                                                 FieldSize = 5
    end                                                                           end
    item                                                                          item
      FieldName = 'VEHICLE_REG'                                                     FieldName = 'VEHICLE_REG'
      DataType = atString                                                           DataType = atString
      FieldSize = 32                                                                FieldSize = 32
    end                                                                           end
    item                                                                          item
      FieldName = 'CREATED_BY'                                                      FieldName = 'CREATED_BY'
      DataType = atString                                                           DataType = atString
      FieldSize = 32                                                                FieldSize = 32
    end                                                                           end
    item                                                                          item
      FieldName = 'UPDATED_BY'                                                      FieldName = 'UPDATED_BY'
      DataType = atString                                                           DataType = atString
      FieldSize = 32                                                                FieldSize = 32
    end                                                                           end
    item                                                                          item
      FieldName = 'LDD_ID'                                                          FieldName = 'LDD_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end                                                                           end
    item                                                                          item
      FieldName = 'TRANS_TYPE_ID'                                                   FieldName = 'TRANS_TYPE_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 3                                                                 FieldSize = 3
    end                                                                           end
    item                                                                          item
      FieldName = 'STAGE_ID'                                                        FieldName = 'STAGE_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 1                                                                 FieldSize = 1
    end                                                                           end
    item                                                                          item
      FieldName = 'ACCOUNT_ID'                                                      FieldName = 'ACCOUNT_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end                                                                           end
    item                                                                          item
      FieldName = 'COMMODITY_ID'                                                    FieldName = 'COMMODITY_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end                                                                           end
    item                                                                          item
      FieldName = 'FLN_ID'                                                          FieldName = 'FLN_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end                                                                           end
    item                                                                          item
      FieldName = 'TLN_ID'                                                          FieldName = 'TLN_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end                                                                           end
    item                                                                          item
      FieldName = 'NET_WEIGHT'                                                      FieldName = 'NET_WEIGHT'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 5                                                                 FieldSize = 5
    end                                                                           end
    item                                                                          item
      FieldName = 'CREATED_DATE'                                                    FieldName = 'CREATED_DATE'
      DataType = atDateTime                                                         DataType = atDateTime
      FieldSize = 19                                                                FieldSize = 19
    end                                                                           end
    item                                                                          item
      FieldName = 'UPDATED_DATE'                                                    FieldName = 'UPDATED_DATE'
      DataType = atDate                                                             DataType = atDate
      FieldSize = 10                                                                FieldSize = 10
    end                                                                           end
    item                                                                          item
      FieldName = 'UPDATED_TIME'                                                    FieldName = 'UPDATED_TIME'
      DataType = atTime                                                             DataType = atTime
      FieldSize = 8                                                                 FieldSize = 8
    end                                                                           end
    item                                                                          item
      FieldName = 'TRAILER_REG'                                                     FieldName = 'TRAILER_REG'
      DataType = atString                                                           DataType = atString
      FieldSize = 6                                                                 FieldSize = 6
    end                                                                           end
    item                                                                          item
      FieldName = 'TRANSACTION_DATE'                                                FieldName = 'TRANSACTION_DATE'
      DataType = atDateTime                                                         DataType = atDateTime
      FieldSize = 19                                                                FieldSize = 19
    end                                                                           end
    item                                                                          item
      FieldName = 'IOX'                                                             FieldName = 'IOX'
      DataType = atString                                                           DataType = atString
      FieldSize = 1                                                                 FieldSize = 1
    end                                                                           end
    item                                                                          item
      FieldName = 'SHIP_ID'                                                         FieldName = 'SHIP_ID'
      DataType = atLongInt                                                          DataType = atLongInt
      FieldSize = 9                                                                 FieldSize = 9
    end>                                                                          end>
  DataDef.Delimiter = '"'                                                       DataDef.Delimiter = '"'
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
  DataDef.Separator = ','                                                  <>   DataDef.Separator = ';'
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
  DataDef.RecordFormat = rfCustom                                          =    DataDef.RecordFormat = rfCustom
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
  DataDef.FormatSettings.DateSeparator = '/'                               +-
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
  DataDef.FormatSettings.ShortDateFormat = 'DD/MM/YYYY'                    =    DataDef.FormatSettings.ShortDateFormat = 'DD/MM/YYYY'
  DataDef.FormatSettings.ShortTimeFormat = 'HH:mm:ss'                           DataDef.FormatSettings.ShortTimeFormat = 'HH:mm:ss'
  Left = 430                                                                    Left = 430
  Top = 20                                                                      Top = 20
end                                                                           end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------

这是我为此编写的一个测试,它通过了。

procedure TMyTestObject.TestReaderStaterfCustom;
var
  LOriginalReader: TFDBatchMoveTextReader;
  LRestoredReader: TFDBatchMoveTextReader;
const
  LDelimiter    = '|';
  LSeparator   = ',';
begin
  LOriginalReader := TFDBatchMoveTextReader.Create( nil );
  LRestoredReader := TFDBatchMoveTextReader.Create( nil );
  try
    LOriginalReader.DataDef.RecordFormat := rfCustom;
    LOriginalReader.DataDef.Delimiter    := LDelimiter;
    LOriginalReader.DataDef.Separator    := LSeparator;

    LRestoredReader.State := LOriginalReader.State;

    Assert.AreEqual( LOriginalReader.State, LRestoredReader.State, 'LOriginalReader.State, LRestoredReader.State (after setting)' );
    Assert.AreEqual( LOriginalReader.DataDef.Delimiter, LRestoredReader.DataDef.Delimiter );
    Assert.AreEqual( LOriginalReader.DataDef.Separator, LRestoredReader.DataDef.Separator );
    Assert.AreEqual( LDelimiter, LRestoredReader.DataDef.Delimiter );
    Assert.AreEqual( LSeparator, LRestoredReader.DataDef.Separator );

  finally
    LOriginalReader.Free;
    LRestoredReader.Free;
  end;

end;

但是当我尝试在我的应用程序中使用它时它失败了。 我已经将一些日志记录在 setter 中,如下所示:

procedure TFDBatchMoveTextReaderHelper.SetState( const Value: String );
begin
  CodeSite.Send( 'TFDBatchMoveTextReaderHelper.SetState', Value );
  StrtoComp( Value, Self );
  CodeSite.Send( 'self.DataDef.Separator', self.DataDef.Separator );
end;

将分隔符记录为 self.DataDef.Separator = ; 这是没有意义的,因为状态字符串字符串中的值是:

DataDef.Delimiter = '"'
DataDef.Separator = ','
DataDef.RecordFormat = rfCustom
DataDef.FormatSettings.DateSeparator = '/'
DataDef.FormatSettings.ShortDateFormat = 'DD/MM/YYYY'
DataDef.FormatSettings.ShortTimeFormat = 'HH:mm:ss'

这就是我在应用程序中实际使用它的方式:

      lConn := TFDConnection.Create( nil );
  try
    lConn.ConnectionDefName := AConnectionDefName;
    lMover                  := TFDBatchMove.Create( lConn );
    lMemTable               := TFDMemTable.Create( lConn );
    lReader                 := TFDBatchMoveTextReader.Create( lConn );
    lReader.State           := AReaderState;
    lReader.FileName        := lTempFileName;
    lWriter                 := TFDBatchMoveDataSetWriter.Create( lConn );
    lWriter.Dataset         := lMemTable;
    lQuery                  := TFDQuery.Create( lConn );
    lQuery.Connection       := lConn;
    lQuery.SQL.Text         := ATargetSQL;
    try
      lQuery.Prepare;
    except
      on E: Exception do
      begin
        CodeSite.SendException( Format( 'Error perparing query: %s', [ ATargetSQL ] ), E );
        raise;
      end
    end;
    lMover.Reader := lReader;
    lMover.Writer := lWriter;

在应用状态字符串后,我已经解决了这个设置分隔符和定界符的问题。 在我的休息中,我发现状态保存的顺序导致了问题。 如果 DataDef.RecordFormat 在 DataDef.Delimiter 和 DataDef.Separator 之前,它就起作用了。 但是我无法控制它是如何保存的,所以我在读回它时已经破解了它。

procedure TFDBatchMoveTextReaderHelper.SetState( const Value: String );
var
  RegEx: TRegEx;
  Match: TMatch;
const
  PatternRecordFormat = 'DataDef\.RecordFormat *= *(rfCustom)';
  PatternSeparator    = 'DataDef\.Separator *= *''(.)''';
  PatternDelimiter    = 'DataDef\.Delimiter *= *''(.)''';
begin
  StrtoComp( Value, Self );

  RegEx := TRegEx.Create( PatternRecordFormat, [ roIgnoreCase, roMultiLine ] );
  Match := RegEx.Match( Value );
  if Match.Success and ( Match.Groups.Count > 1 ) then
  begin
    RegEx := TRegEx.Create( PatternSeparator, [ roIgnoreCase, roMultiLine ] );
    Match := RegEx.Match( Value );
    if Match.Success and ( Match.Groups.Count > 1 ) then
      Self.DataDef.Separator := ( Match.Groups[ 1 ].Value + ',' )[ 1 ];

    RegEx := TRegEx.Create( PatternDelimiter, [ roIgnoreCase, roMultiLine ] );
    Match := RegEx.Match( Value );
    if Match.Success and ( Match.Groups.Count > 1 ) then
      Self.DataDef.Delimiter := ( Match.Groups[ 1 ].Value + '"' )[ 1 ];
  end;

end;

不是我知道的最好的答案,但这是我能想出的全部。 这是我的测试以确认它有效。

[ Test ]
[ TestCase( 'Comma Double Quote', 'rfCommaDoubleQuote' ) ]
[ TestCase( 'Semicolon Double Quote', 'rfSemicolonDoubleQuote' ) ]
[ TestCase( 'Tab Double Quote', 'rfTabDoubleQuote' ) ]
[ TestCase( 'Fixed Length', 'rfFixedLength' ) ]
[ TestCase( 'Field Per Line', 'rfFieldPerLine' ) ]
[ TestCase( 'Bar Double Quote', 'rfCustom' ) ]
procedure TestReaderState( const ARecordFormat: TFDTextRecordFormat );


procedure TMyTestObject.TestReaderState( const ARecordFormat: TFDTextRecordFormat );
var
  LOriginalReader: TFDBatchMoveTextReader;
  LRestoredReader: TFDBatchMoveTextReader;
  LDelimiter     : Char;
  LSeparator     : Char;
  LWithFieldNames: Boolean;
begin
  LOriginalReader := TFDBatchMoveTextReader.Create( nil );
  LRestoredReader := TFDBatchMoveTextReader.Create( nil );
  try
    case ARecordFormat of
      rfCommaDoubleQuote:
        begin
          LDelimiter := #34;
          LSeparator := #44;
        end;
      rfSemicolonDoubleQuote:
        begin
          LDelimiter := #34;
          LSeparator := #59;
        end;
      rfTabDoubleQuote:
        begin
          LDelimiter := #34;
          LSeparator := #9;
        end;
      rfFixedLength:
        begin
          LDelimiter      := #0;
          LSeparator      := #0;
          LWithFieldNames := False;
        end;
      rfFieldPerLine:
        begin
          LDelimiter      := #0;
          LSeparator      := #0;
          LWithFieldNames := False;
        end;
      rfCustom:
        begin
          LDelimiter := #124;
          LSeparator := #44;
        end;
    else
      begin
        LDelimiter := #34;
        LSeparator := #59;
      end;
    end;
    LOriginalReader.DataDef.RecordFormat := ARecordFormat;
    if LOriginalReader.DataDef.RecordFormat = ARecordFormat then
    begin
      LOriginalReader.DataDef.Delimiter := LDelimiter;
      LOriginalReader.DataDef.Separator := LSeparator;
    end;

    LRestoredReader.State := LOriginalReader.State;

    Assert.AreEqual( LOriginalReader.State, LRestoredReader.State, 'LOriginalReader.State, LRestoredReader.State (after setting)' );
    Assert.AreEqual( LOriginalReader.DataDef.Delimiter, LRestoredReader.DataDef.Delimiter );
    Assert.AreEqual( LOriginalReader.DataDef.Separator, LRestoredReader.DataDef.Separator );
    Assert.AreEqual( LDelimiter, LRestoredReader.DataDef.Delimiter );
    Assert.AreEqual( LSeparator, LRestoredReader.DataDef.Separator );
    Assert.AreEqual( LOriginalReader.DataDef.WithFieldNames, LRestoredReader.DataDef.WithFieldNames )

  finally
    LOriginalReader.Free;
    LRestoredReader.Free;
  end;

end;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM