Delphi 如何在LoadFromFile之后更改TClientDataSet中fielddef size的大小

Delphi 如何在LoadFromFile之后更改TClientDataSet中fielddef size的大小,delphi,Delphi,在使用LoadFromFile之后,我很难更改TClientDataSet中fielddefs的大小。 是否有人有一个很好的方法来更改给定ClientDataSet的大小,但仍保留所有其他内容。TDataSet的实现方式,有虚拟方法来分配和释放记录缓冲区,以及从该缓冲区获取和设置值。大多数数据集子体为缓冲区保留一块连续内存,因此,如果三个字段的长度分别为4、6和20字节,则字段1将从位置0开始,字段2将从位置4开始,字段3将从位置10开始 如果要在数据集打开时更改字段大小,则必须调整所有缓冲区的

在使用LoadFromFile之后,我很难更改TClientDataSet中fielddefs的大小。
是否有人有一个很好的方法来更改给定ClientDataSet的大小,但仍保留所有其他内容。

TDataSet的实现方式,有虚拟方法来分配和释放记录缓冲区,以及从该缓冲区获取和设置值。大多数数据集子体为缓冲区保留一块连续内存,因此,如果三个字段的长度分别为4、6和20字节,则字段1将从位置0开始,字段2将从位置4开始,字段3将从位置10开始

如果要在数据集打开时更改字段大小,则必须调整所有缓冲区的大小,否则会遇到麻烦。没有虚拟的方法来调整缓冲区的大小,所以我认为这可能是不可行的


方法是将内容从原始CD复制到具有不同字段大小的新CD。按值为其赋值,或使用TDataSetProvider。如果使用提供程序(最佳方法),但不知道确切的定义,则仍需要遍历源数据集字段,并将其添加到具有正确大小的目标中。

TDataSet的实现方式,有一些虚拟方法可以分配和释放记录缓冲区,也可以从该缓冲区获取和设置值。大多数数据集子体为缓冲区保留一块连续内存,因此,如果三个字段的长度分别为4、6和20字节,则字段1将从位置0开始,字段2将从位置4开始,字段3将从位置10开始

如果要在数据集打开时更改字段大小,则必须调整所有缓冲区的大小,否则会遇到麻烦。没有虚拟的方法来调整缓冲区的大小,所以我认为这可能是不可行的


方法是将内容从原始CD复制到具有不同字段大小的新CD。按值为其赋值,或使用TDataSetProvider。如果您使用提供程序(最佳方法),但不知道确切的定义,您仍需要遍历源数据集字段,并将其添加到具有正确大小的目标中。

您可以使用旧数据集的字段定义创建新数据集,关键点是
TFieldDefs.Assign
。下面是一个小例子:

// insert test data
procedure TForm1.InsertRecord(DataSet: TDataSet; ID: Integer; const Name: string);
begin
  DataSet.Insert;
  try
    DataSet.Fields[0].AsInteger := ID;
    DataSet.Fields[1].AsString := Name;
    DataSet.Post;
  except
    DataSet.Cancel;
    raise;
  end;
end;

// create the original dataset
procedure TForm1.Button1Click(Sender: TObject);
var
  DataSet: TClientDataSet;
begin
  DataSet := TClientDataSet.Create(nil);
  try
    DataSet.FieldDefs.Add('ID', ftInteger);
    DataSet.FieldDefs.Add('NAME', ftString, 20);
    DataSet.CreateDataSet;
    DataSet.LogChanges := False;
    InsertRecord(DataSet, 1, 'Hello');
    InsertRecord(DataSet, 2, 'World!');
    DataSet.SaveToFile(ExtractFilePath(Application.ExeName) + 'old.xml', dfXML);
  finally
    DataSet.Free;
  end;
end;

// create the new dataset
procedure TForm1.Button2Click(Sender: TObject);
var
  OldDataSet, NewDataSet: TClientDataSet;
begin
  OldDataSet := nil;
  NewDataSet := nil;
  try
    OldDataSet := TClientDataSet.Create(nil);
    OldDataSet.LoadFromFile(ExtractFilePath(Application.ExeName) + 'old.xml');

    NewDataSet := TClientDataSet.Create(nil);
    NewDataSet.FieldDefs.Assign(OldDataSet.FieldDefs);
    NewDataSet.FieldDefs[1].Size := 30;
    NewDataSet.CreateDataSet;
    NewDataSet.LogChanges := False;

    OldDataSet.First;
    while not OldDataSet.EOF do
    begin
      InsertRecord(NewDataSet, OldDataSet.Fields[0].AsInteger, OldDataSet.Fields[1].AsString);

      OldDataSet.Next;
    end;

    NewDataSet.SaveToFile(ExtractFilePath(Application.ExeName) + 'new.xml', dfXML);
  finally
    OldDataSet.Free;
    NewDataSet.Free;
  end;
end;

您可以使用旧数据集的FieldDefs创建新数据集。关键点是
TFieldDefs.Assign
。下面是一个小例子:

// insert test data
procedure TForm1.InsertRecord(DataSet: TDataSet; ID: Integer; const Name: string);
begin
  DataSet.Insert;
  try
    DataSet.Fields[0].AsInteger := ID;
    DataSet.Fields[1].AsString := Name;
    DataSet.Post;
  except
    DataSet.Cancel;
    raise;
  end;
end;

// create the original dataset
procedure TForm1.Button1Click(Sender: TObject);
var
  DataSet: TClientDataSet;
begin
  DataSet := TClientDataSet.Create(nil);
  try
    DataSet.FieldDefs.Add('ID', ftInteger);
    DataSet.FieldDefs.Add('NAME', ftString, 20);
    DataSet.CreateDataSet;
    DataSet.LogChanges := False;
    InsertRecord(DataSet, 1, 'Hello');
    InsertRecord(DataSet, 2, 'World!');
    DataSet.SaveToFile(ExtractFilePath(Application.ExeName) + 'old.xml', dfXML);
  finally
    DataSet.Free;
  end;
end;

// create the new dataset
procedure TForm1.Button2Click(Sender: TObject);
var
  OldDataSet, NewDataSet: TClientDataSet;
begin
  OldDataSet := nil;
  NewDataSet := nil;
  try
    OldDataSet := TClientDataSet.Create(nil);
    OldDataSet.LoadFromFile(ExtractFilePath(Application.ExeName) + 'old.xml');

    NewDataSet := TClientDataSet.Create(nil);
    NewDataSet.FieldDefs.Assign(OldDataSet.FieldDefs);
    NewDataSet.FieldDefs[1].Size := 30;
    NewDataSet.CreateDataSet;
    NewDataSet.LogChanges := False;

    OldDataSet.First;
    while not OldDataSet.EOF do
    begin
      InsertRecord(NewDataSet, OldDataSet.Fields[0].AsInteger, OldDataSet.Fields[1].AsString);

      OldDataSet.Next;
    end;

    NewDataSet.SaveToFile(ExtractFilePath(Application.ExeName) + 'new.xml', dfXML);
  finally
    OldDataSet.Free;
    NewDataSet.Free;
  end;
end;

你能不能更具体一点你想做什么?你能不能更具体一点你想做什么?谢谢TOndrej。早些时候,我用类似的方法解决了这个问题。“pre”CD将打开一个xml文件。然后,程序将从预CD->目标CD复制fielddefs(分配方法)。然后检查FieldDef是否存在字段名,如果发现该字段名的大小不正确,请更正。然后,将预CD的值复制到目标CD。在此复制过程中,事件被设置为nil,并在结束时再次返回。只读字段也是如此。目标CD保存到XML文件中。检查此文件此过程似乎运行良好。谢谢TOndrej。早些时候,我用类似的方法解决了这个问题。“pre”CD将打开一个xml文件。然后,程序将从预CD->目标CD复制fielddefs(分配方法)。然后检查FieldDef是否存在字段名,如果发现该字段名的大小不正确,请更正。然后,将预CD的值复制到目标CD。在此复制过程中,事件被设置为nil,并在结束时再次返回。只读字段也是如此。目标CD保存到XML文件中。检查此文件此过程似乎运行良好。