2009-08-15 12 views
2

"Record.somefield"を明示的に実行せずにレコードを取得し、すべてのフィールドをプログラム的に処理する方法はありますか?Delphi:未知の構造のレコードを解析する

私がやりたいことは、レコードをINIファイルとして保存/ロードする一般的な機能です。レコードを削除または追加するたびに保存/読み込み機能を書き直すことなくフィールドを追加または削除できますフィールドをレコードに追加します。私が提出された型付きを保存することはできませんので、ところで、私はこれをしたい理由がある

THuman = record 
    age: integer; 
    country: string ; 
end; 
... 
myPerson: THuman; 
... 
    foreach Field in myPerson do 
    begin 
     if Field.value is String then ini.WriteString('Group', Field.Name, Field.value); 
     if Field.value is integer then ini.WriteInteger('Group', Field.Name, Field.value); 
    end; 

:私はこのようないくつかの方法(擬似コード)で反復したい言い換えれば

バインドされていない文字列を使用します。また、ファイルが人間に読めるものであることは私には有益です。だから私はそれらとINIファイルを保存しています。

+0

は、DFMファイルを取得するための例を掲載しました。まもなく私のブログに掲載します。 –

+0

また、この質問の受け入れられたコメントを見ることもできます:http://stackoverflow.com/questions/1293504/what-is-the-best-way-to-serialize-delphi-application-configuration RTTIを自分でやること。 –

答えて

0

このような種類のレコードをクラスに変換することをお勧めします。

5

チャンスはありません。レコードには実行時の型情報が添付されていません。代わりに公開されたプロパティを持つクラスを使用した場合は、jvclのTApplicationStorage/TFormStorageコンポーネント、Delphi DFMストリーミングシステム、さまざまなインターネットサイトなどを参照してください。

+0

これは、レコードにプロパティを持たせることができるdelphiの高度なレコード構造で動作しますか? –

+0

レコードが公開プロパティを持つことはできません。プライベートとパブリックのみです(継承をサポートしていないため保護されていません)。 – dummzeuch

2

名前と値のペアでいっぱいになったTStringListを使用できます。

事前に構造を知る必要はありません。エレメントは一度に1つずつ歩いたり、インデックスでアドレスを調べたりするのが簡単で、iniファイルに保存するのに適しています。

TIniFile.ReadSectionValuesを使用して、iniファイルのセクションからTStringListを読み込みます。

var 
    i: Integer; 
begin 
    FList := TStringList.Create; 
    FList.Add('a=one'); 
    FList.Add('b=two'); 
    FList.Add('c=three'); 

    Label1.Caption := FList.Values['b']; 

    for i := 0 to FList.Count - 1 do 
    Memo1.Lines.Add(FList.Names[i] + ' - ' + FList.Values[FList.Names[i]]); 
+1

私はこれを実際にCSV形式にしようとしましたが、文字列へのすべてのデータ変換のために利点が減りました。この場合、私はこのコンセプトに合わせてさらにフォーマットする必要がある複数行の文字列を持っています。 –

+0

TStringListの代わりにTMemIniFileを使用すると、変換の一部を回避できます。複数行の文字列の解決法は、ロード後に保存して戻すために中立文字(#7)でCRLFを動かすことです。 –

0

はい、ただし、レコードをオブジェクトにラップし、フィールドをプロパティとして公開する必要があります。 INIファイルを読み書きするためにプロパティを繰り返し処理できます。私はこれをたくさんしてきました、RTTIは非常に便利です。 Bri

1

レコードにはRTTIを含めることができますが、少なくとも1つのリファレンスカウントフィールド(文字列またはインターフェイスなど)がある場合に限ります。そしてその記録RTTIは非常に限られているので、あなたを助けるものではありません。

Delphi LiveにDelphi 2010でRTTIが大幅に拡張される予定であることから、RTTIも拡張されている可能性があります。

TComponentからクラスを派生し、組み込みのストリーミングメカニズムを使用するか、RTTIを使用してINIファイルとの間でやり取りすることをお勧めします。 はるかに簡単です!

--jeroen

編集:例

まずコンポーネント:

unit IntegerValueComponentUnit; 

interface 

uses 
    Classes; 

type 
    TCustomIntegerValueComponent = class(TComponent) 
    strict private 
    FIntegerValue: Integer; 
    strict protected 
    function GetIntegerValue: Integer; virtual; 
    procedure SetIntegerValue(const Value: Integer); virtual; 
    public 
    property IntegerValue: Integer read GetIntegerValue write SetIntegerValue; 
    end; 

    TIntegerValueComponent = class(TCustomIntegerValueComponent) 
    published 
    property IntegerValue; 
    end; 

implementation 

function TCustomIntegerValueComponent.GetIntegerValue: Integer; 
begin 
    Result := FIntegerValue; 
end; 

procedure TCustomIntegerValueComponent.SetIntegerValue(const Value: Integer); 
begin 
    FIntegerValue := Value; 
end; 

end. 

次いで、得られたDFMファイル:

object TIntegerValueComponent 
    IntegerValue = 33 
end 

DFMファイルを編集することが合理的に容易であることiniファイルと同様に、エラーが発生する可能性があるため、一般ユーザーが編集することはお勧めしません。

ストリームへの/からの基本ストリーミングと、バイナリフォーマットからテキストフォーマットへの変換が必要です(メモリが私に正しければ、テキストフォーマットはDelphi 5以降のデフォルトです)読むのがはるかに簡単です)。

unit ComponentDfmUnit; 

interface 

uses 
    Classes, IntegerValueComponentUnit; 

type 
    TComponentDfm = class 
    public 
    class function FromDfm(const Dfm: string): TComponent; static; 
    class function GetDfm(const Component: TComponent): string; static; 
    class function LoadFromDfm(const FileName: string): TComponent; static; 
    class procedure SaveToDfm(const Component: TComponent; const FileName: string); static; 
    end; 

implementation 

class function TComponentDfm.FromDfm(const Dfm: string): TComponent; 
var 
    MemoryStream: TMemoryStream; 
    StringStream: TStringStream; 
begin 
    MemoryStream := TMemoryStream.Create; 
    try 
    StringStream := TStringStream.Create(Dfm); 
    try 
     ObjectTextToBinary(StringStream, MemoryStream); 
     MemoryStream.Seek(0, soFromBeginning); 
     Result := MemoryStream.ReadComponent(nil); 
    finally 
     StringStream.Free; 
    end; 
    finally 
    MemoryStream.Free; 
    end; 
end; 

class function TComponentDfm.GetDfm(const Component: TComponent): string; 
var 
    MemoryStream: TMemoryStream; 
    StringStream: TStringStream; 
begin 
    MemoryStream := TMemoryStream.Create; 
    try 
    MemoryStream.WriteComponent(Component); 
    StringStream := TStringStream.Create(''); 
    try 
     MemoryStream.Seek(0, soFromBeginning); 
     ObjectBinaryToText(MemoryStream, StringStream); 
     Result := StringStream.DataString; 
    finally 
     StringStream.Free; 
    end; 
    finally 
    MemoryStream.Free; 
    end; 
end; 

class function TComponentDfm.LoadFromDfm(const FileName: string): TComponent; 
var 
    DfmStrings: TStrings; 
begin 
    DfmStrings := TStringList.Create; 
    try 
    DfmStrings.LoadFromFile(FileName); 
    Result := TComponentDfm.FromDfm(DfmStrings.Text); 
    finally 
    DfmStrings.Free; 
    end; 
end; 

class procedure TComponentDfm.SaveToDfm(const Component: TComponent; const FileName: string); 
var 
    DfmStrings: TStrings; 
begin 
    DfmStrings := TStringList.Create; 
    try 
    DfmStrings.Text := TComponentDfm.GetDfm(Component); 
    DfmStrings.SaveToFile(FileName); 
    finally 
    DfmStrings.Free; 
    end; 
end; 

end. 

し、この例では、(最初​​の形式コードは、フォームのDFM)を動作するはず: 最も重要な線はRegisterClass(TIntegerValueComponent)です。、それは忘れやすいので。コードの残りはかなり簡単です。

また、コンポーネントをクリップボードにコピーして貼り付けることもできます。 バイナリ形式を使用してクリップボードとの間でストリーミングされます。

const 
    FileName = 'IntegerValue.dfm'; 

procedure TStreamingDemoForm.ButtonEnabledTimerTimer(Sender: TObject); 
begin 
    SaveButton.Enabled := SaveStyleRadioGroup.ItemIndex <> -1; 
    LoadButton.Enabled := SaveButton.Enabled; 
    if SaveStyleRadioGroup.ItemIndex = 0 then 
    LoadButton.Enabled := FileExists(FileName); 
    if SaveStyleRadioGroup.ItemIndex = 1 then 
    LoadButton.Enabled := Clipbrd.Clipboard.HasFormat(CF_COMPONENT); 
end; 

procedure TStreamingDemoForm.LoadButtonClick(Sender: TObject); 
var 
    IntegerValueComponent: TIntegerValueComponent; 
begin 
    IntegerValueComponent := nil; 
    if SaveStyleRadioGroup.ItemIndex = 0 then 
    IntegerValueComponent := LoadUsingFileStream() 
    else 
    IntegerValueComponent := LoadUsingClipboard(); 
    try 
    if Assigned(IntegerValueComponent) then 
     Log('Loaded: %d', [IntegerValueComponent.IntegerValue]) 
    else 
     Log('nil during Load'); 
    finally 
    IntegerValueComponent.Free; 
    end; 
end; 

function TStreamingDemoForm.LoadUsingClipboard: TIntegerValueComponent; 
var 
    Component: TComponent; 
begin 
    Result := nil; 
    RegisterClass(TIntegerValueComponent); 
    Component := Clipboard.GetComponent(nil, nil); 
    if Assigned(Component) then 
    if Component is TIntegerValueComponent then 
     Result := TIntegerValueComponent(Component); 
end; 

function TStreamingDemoForm.LoadUsingFileStream: TIntegerValueComponent; 
var 
    Component: TComponent; 
begin 
    Result := nil; 
    RegisterClass(TIntegerValueComponent); 
    Component := TComponentDfm.LoadFromDfm(FileName); 
    if Assigned(Component) then 
    if Component is TIntegerValueComponent then 
     Result := TIntegerValueComponent(Component); 
end; 

procedure TStreamingDemoForm.Log(const Line: string); 
begin 
    LogMemo.Lines.Add(Line); 
end; 

function TStreamingDemoForm.Log(const Mask: string; const Args: array of const): string; 
begin 
    Log(Format(Mask, Args)); 
end; 

procedure TStreamingDemoForm.SaveButtonClick(Sender: TObject); 
var 
    IntegerValueComponent: TIntegerValueComponent; 
begin 
    IntegerValueComponent := TIntegerValueComponent.Create(nil); 
    try 
    IntegerValueComponent.IntegerValue := ValueToSaveSpinEdit.Value; 
    if SaveStyleRadioGroup.ItemIndex = 0 then 
     SaveUsingFileStream(IntegerValueComponent) 
    else 
     SaveUsingClipboard(IntegerValueComponent); 
    Log('Saved: %d', [IntegerValueComponent.IntegerValue]) 
    finally 
    IntegerValueComponent.Free; 
    end; 
end; 

procedure TStreamingDemoForm.SaveUsingClipboard(IntegerValueComponent: TIntegerValueComponent); 
begin 
    Clipboard.SetComponent(IntegerValueComponent); 
end; 

procedure TStreamingDemoForm.SaveUsingFileStream(IntegerValueComponent: TIntegerValueComponent); 
begin 
    TComponentDfm.SaveToDfm(IntegerValueComponent, Filename); 
end; 

最後に、フォームのDFM:

object StreamingDemoForm: TStreamingDemoForm 
    Left = 0 
    Top = 0 
    Caption = 'StreamingDemoForm' 
    ClientHeight = 348 
    ClientWidth = 643 
    Color = clBtnFace 
    Font.Charset = DEFAULT_CHARSET 
    Font.Color = clWindowText 
    Font.Height = -11 
    Font.Name = 'Tahoma' 
    Font.Style = [] 
    OldCreateOrder = False 
    DesignSize = (
    643 
    348) 
    PixelsPerInch = 96 
    TextHeight = 13 
    object ValueToSaveLabel: TLabel 
    Left = 14 
    Top = 8 
    Width = 65 
    Height = 13 
    Caption = '&Value to save' 
    FocusControl = ValueToSaveSpinEdit 
    end 
    object ValueToSaveSpinEdit: TSpinEdit 
    Left = 95 
    Top = 5 
    Width = 121 
    Height = 22 
    MaxValue = 0 
    MinValue = 0 
    TabOrder = 0 
    Value = 0 
    end 
    object SaveButton: TButton 
    Left = 14 
    Top = 33 
    Width = 75 
    Height = 25 
    Caption = '&Save' 
    TabOrder = 1 
    OnClick = SaveButtonClick 
    end 
    object LoadButton: TButton 
    Left = 14 
    Top = 64 
    Width = 75 
    Height = 25 
    Caption = '&Load' 
    TabOrder = 2 
    OnClick = LoadButtonClick 
    end 
    object LogMemo: TMemo 
    Left = 14 
    Top = 95 
    Width = 621 
    Height = 245 
    Anchors = [akLeft, akTop, akRight, akBottom] 
    Lines.Strings = (
     'LogMemo') 
    TabOrder = 3 
    end 
    object SaveStyleRadioGroup: TRadioGroup 
    Left = 95 
    Top = 30 
    Width = 121 
    Height = 59 
    Caption = 'Save st&yle' 
    Items.Strings = (
     'Value.dfm' 
     'Clipboard') 
    TabOrder = 4 
    end 
    object ButtonEnabledTimer: TTimer 
    Interval = 100 
    OnTimer = ButtonEnabledTimerTimer 
    Left = 270 
    Top = 6 
    end 
end 
+0

TcomponentストリーミングメカニズムやRTTIを使用してINIファイルに取り込む方法の例を教えてください。 Web参照リンクは問題ありません。 –

関連する問題