• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

【delphi】ClientDataSet详细解读

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

TClientDataSet的基本属性和方法

  TClientDataSet控件继承自TDataSet,其数据存储文件格式扩展名为 .cds/.xml,是基于文件型数据存储和操作的控件。

  该控件封装了对数据进行操作处理的接口和功能,而本身并不依赖其它数据库驱动程序,基本上能满足单机"瘦"数据库应用程序的需要。

FieldDefs: 字段定义列表属性

  可通过单击属性编辑器中的属性编辑按钮,或在该控件上单击右键选择弹出菜单中的"Fields Editor"菜单进行字段编辑。设置完此属性后,实际上就相当于定义了表的结构;

  如果想装入已有的数据表的结构和数据,可通过单击右键选择弹出菜单中的"Assign Local Data"菜单,从弹出对话框中选取当前窗体中已与数据库连接好的数据集控件名称即可(当前窗体中必须已放置好要套用的数据集控件并打开激活)

  使用注意对于自定义的字段名表,该属性编辑完后,该控件仍然无法打开。必须右键单击该控件,选择弹出菜单中的"Create DataSet"菜单,让该控件以上述编辑的字段列表为依据,创建数据集后,才能够被激活打开和使用。否则,会出现类似"ClientDataSet1: Missing data provider or data packet."的错误(包括在运行期,运行期可调用该控件的CreateDataSet方法,从而动态定义字段和表)

FileName:数据存储文件的名称

  因该控件是基于文件型的数据操作控件,因此,必须指定所操作的数据文件名称(默认扩展名称.cds),从而打开和激活该控件,进而进行数据编辑。

  例如:利用此属性打开指定的.cds文件

var
Path: string;
begin
 Path := ExtractFilePath(Application.ExeName); //取得可执行文件路径
 CDataSet1.FileName := Path + 'test.cds';
 CDataSet1.Open;
end;
View Code

CreateDataSet以FieldDefs中的字段名表为结构建立数据集,常用来进行动态定义表。

  例如:动态创建一具有姓名和年龄两个字段的数据集

//创建字段名表
CDataSet.FieldDefs.Clear;
with CDataSet.FieldDefs.AddFieldDef do
begin
 Name := 'Name';
 Size := 10;
 DataType := ftString;
end;
with CDataSet.FieldDefs.AddFieldDef do
begin
 Name := 'Age';
 DataType := ftInteger;
end;
//动态创建数据集
CDataSet.CreateDataSet;
//激活和打开该数据集
CDataSet.Open;
View Code

Open打开和激活数据集控件,从而进行数据编辑

  1. 如果指定了FileName属性,则直接用Open方法即可打开和激活该控件
  2. 如果未指定FileName属性,可用动态创建和打开数据集,进而操作数据

LoadFromFile/SaveToFile从文件中装入表结构和数据以及存储数据到文件

  例如::将数据集的数据存储到指定文件中

CDataSet.SaveToFile('c:\windows\desktop\test.cds');
View Code

Filter, Filtered: 过滤筛选属性

  说明:用于筛选指定条件的记录,用法同一般数据集控件,略。

  例如:在已经激活打开的数据集中筛选性别为男性的记录

CDataSet.Close;
CDataSet.Filter := '性别=''' + '' + '''';
CDataSet.Filtered := True;
CDataSet.Open;
View Code

其它方法

  First(到首),Prior(向前),Next(向后),Last(到尾),Edit(编辑),CanCel(取消编辑),Post(保存),Insert(插入记录),Append(添加记录),Delete(删除),Refresh(数据刷新)等

说明

  1. 当指定了FileName属性时,其Post方法可将数据存入指定的文件中,类似其SaveToFile方法;
  2. 如果未指定存储文件名,则Post方法只将数据存储在RAM中。
  3. 其它方法,同一般数据集控件使用方法

 使用TClientDataSet控件的应用程序发布的注意事项

  使用TClientDataSet控件的程序发布时不需要任何数据库驱动程序,大大节省了安装文件的大小。

  但是,在发布程序时别忘了将Windows系统目录下midas.dll与应用程序一起发布,否则,程序可能无法正常运行。

 


手动建立数据集

  示例代码:

//放置控件: ClientDataSet1、DataSource1、DBGrid1、Button1, 然后

procedure TForm1.Button1Click(Sender: TObject);
begin
  { 添加字段 }
  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    Name := 'ID';
    DataType := ftInteger;
  end;

  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    Name := 'Name';
    DataType := ftString;
    Size := 12; { ftString 类型的 Size 默认 20 }
  end;

  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    Name := 'Age';
    DataType := ftWord;
  end;

  with ClientDataSet1.FieldDefs.AddFieldDef do
  begin
    Name := 'Sex';
    DataType := ftBoolean;
  end;

  { 构建数据集, 不可缺少的一步 }
  ClientDataSet1.CreateDataSet;

  { 显示; 如果在设计时已挂接或不需要显示, 可省略下两行 }
  DataSource1.DataSet := ClientDataSet1;
  DBGrid1.DataSource := DataSource1;

  { 添加数据 }
  ClientDataSet1.AppendRecord([1, '张三', 33, True]);
  ClientDataSet1.AppendRecord([2, '李四', 44, False]);
  ClientDataSet1.AppendRecord([3, '王五', 55, True]);

  { 保存为 cds 或 XML }
  ClientDataSet1.SaveToFile('C:\Temp\TestBinary.cds');
  ClientDataSet1.SaveToFile('C:\Temp\TestXMLUTF8.xml', dfXMLUTF8);
end;
View Code

  代码可另写为(下面这种方法简单, 但上一种方法可设置更多选项):

procedure TForm1.Button1Click(Sender: TObject);
begin
  { 添加字段 }
  with  ClientDataSet1.FieldDefs do
  begin
    Add('ID', ftInteger);
    Add('Name', ftString, 12);
    Add('Age', ftWord);
    Add('Sex', ftBoolean);
  end;

  { 构建数据集, 不可缺少的一步 }
  ClientDataSet1.CreateDataSet;

  { 显示; 如果在设计时已挂接或不需要显示, 可省略下两行 }
  DataSource1.DataSet := ClientDataSet1;
  DBGrid1.DataSource := DataSource1;

  { 插入数据 }
  ClientDataSet1.InsertRecord([1, '张三', 33, True]);
  ClientDataSet1.InsertRecord([2, '李四', 44, False]);
  ClientDataSet1.InsertRecord([3, '王五', 55, True]);

  { 保存为 cds 或 XML }
  ClientDataSet1.SaveToFile('C:\Temp\TestBinary.cds');
  ClientDataSet1.SaveToFile('C:\Temp\TestXMLUTF8.xml', dfXMLUTF8);
end;
View Code

 


 数据读取 

  方法介绍

TClientDataSet.Fields[];           { 字段集合; 它比 FieldList 有更多功能, 如可获取嵌套字段 }
TClientDataSet.FieldList[];        { 字段列表; 它比 Fields 轻便, 如果只是取值用它快一些 }
TClientDataSet.FieldByName();      { 根据字段名称获取字段对象; 获取一个字段对象时它比上两个快 }
TClientDataSet.FindField();        { 根据字段名称查找字段对象 }
TClientDataSet.FieldValues[];      { 根据字段名称获取字段值; 如果仅是获取字段值, 这个最快 }
TClientDataSet.First;              { 到第一个记录 }
TClientDataSet.Next;               { 到下一个记录 }
TClientDataSet.Last;               { 到最后一个记录 }
TClientDataSet.Prior;              { 到上一个记录 }
TClientDataSet.RecNo;              { 设置或读取当前记录的位置 }
TClientDataSet.Bof;                { 当前位置是否是第一个记录 }
TClientDataSet.Eof;                { 当前位置是否是最后一个记录 }
TClientDataSet.RecordSize;         { 一个记录的大小; 所谓一个记录就是当前行的所有字段 }
TClientDataSet.RecordCount;        { 记录总数; 也就是总行数 }
TClientDataSet.GetFieldList();     { 根据指定的几个字段名获取字段对象的列表 }
TClientDataSet.GetFieldData();     { 把指定字段的值写入一个缓冲区 }
TClientDataSet.GetCurrentRecord(); { 把当前记录(不包括 Bolb 字段)写入到一个缓冲区 }
View Code
  1. 读取字段的结构信息可以使用 TFieldDef 对象(一般来源于 FieldDefs 或 FieldDefList);
  2. 现在要读取其中的数据, 应该使用 TField 对象(一般来源于 Fields 或 FieldList).
  3. Fields[0]、Fields[1] ... Fields[n] 获取的是当前行的第几个字段, 可用 Next、RecNo 等指定当前位置(行).

  数据读取示例

  例子使用了 Common Files\CodeGear Shared\Data\holdings.xml, 若更换文件需调整代码

  这是 holdings.xml 的字段信息

ACCT_NBR  { 类型是 r8, 对应 ftFloat, 相当于 Double }
SYMBOL    { 类型是 string, 对应 ftString, 相当于 AnsiString; 指定 Size=7, 加上空结束, 大小是 8 }
SHARES    { 类型是 r8, 对应 ftFloat, 相当于 Double }
PUR_PRICE { 类型是 r8, 对应 ftFloat, 相当于 Double }
PUR_DATE  { 类型是 date, 对应 ftInteger, 相当于 Integer }
View Code

  先窗体上放置 ClientDataSet1、DataSource1、DBGrid1、Memo1 和七个 Button

{ 准备数据, 也可在设计时完成 }
procedure TForm1.FormCreate(Sender: TObject);
begin
  ChDir(GetEnvironmentVariable('CommonProgramFiles') + '\CodeGear Shared\Data\');
  ClientDataSet1.LoadFromFile('holdings.xml');
  DBGrid1.DataSource := DataSource1;
  DataSource1.DataSet := ClientDataSet1;
end;

{ 读取字段值的几种方法 }
procedure TForm1.Button1Click(Sender: TObject);
var
  v1,v2,v3,v4,v5,v6,v7,v8,v9: Variant;
  num: Double;
  fName: string;
begin
  { 获取首字段的名称 }
  fName := ClientDataSet1.Fields[0].FieldName;

  { 获取第一个字段值的几种方法: }
  v1 := ClientDataSet1.Fields[0].Value;
  v2 := ClientDataSet1.FieldByName(fName).Value;
  v3 := ClientDataSet1.FindField(fName).Value;
  v4 := ClientDataSet1.FieldValues[fName];
  v5 := ClientDataSet1[fName]; { FieldValues 是默认的数组属性 }
  v6 := ClientDataSet1.FieldList[0].Value;
  v7 := ClientDataSet1.FieldList.FieldByName(fName).Value;
  v8 := ClientDataSet1.FieldList.Find(fName).Value;
  v9 := ClientDataSet1.FieldList.Fields[0].Value;

  { 已知这个字段是 Double 类型的, 可同时转换 }
  num := ClientDataSet1.Fields[0].AsFloat;

  { 查看结果 }
  with Memo1.Lines do begin
    Clear;
    Add(v1); Add(v2); Add(v3); Add(v4); Add(v5); Add(v6); Add(v7); Add(v8);
    Add(FloatToStr(num));
  end;
end;
{ 遍历当前行字段的几种方法 }
procedure TForm1.Button2Click(Sender: TObject);
var
  Field: TField;
  i: Integer;
begin
  Memo1.Clear;
  for Field in ClientDataSet1.Fields do
  begin
    Memo1.Lines.Add(Field.Value);
  end;
  Memo1.Lines.Add('');

  for i := 0 to ClientDataSet1.FieldCount - 1 do
  begin
    Memo1.Lines.Add(ClientDataSet1.Fields[i].Value);
  end;
  Memo1.Lines.Add('');

  for i := 0 to ClientDataSet1.FieldList.Count - 1 do
  begin
    Memo1.Lines.Add(ClientDataSet1.FieldList[i].Value);
  end;
  Memo1.Lines.Add('');
end;

{ First、Next、Last、Prior、RecNo }
procedure TForm1.Button3Click(Sender: TObject);
var
  s1,s2,s3: string;
begin
  { 读取第二行第二个字段 }
  ClientDataSet1.First;
  ClientDataSet1.Next;
  s1 := ClientDataSet1.Fields[1].AsString;

  { 读取倒数第二行第二个字段 }
  ClientDataSet1.Last;
  ClientDataSet1.Prior;
  s2 := ClientDataSet1.Fields[1].AsString;

  { 读取第四行第二个字段 }
  ClientDataSet1.RecNo := 4;
  s3 := ClientDataSet1.Fields[1].AsString;

  { 查看结果 }
  with Memo1.Lines do begin
    Clear;
    Add('第二行第二个字段: ' + s1);
    Add('倒数第二行第二个字段: ' + s2);
    Add('第四行第二个字段: ' + s3);
  end;
end;

{ 遍历指定字段的所有记录 }
procedure TForm1.Button4Click(Sender: TObject);
var
  i: Integer;
begin
  if not ClientDataSet1.Bof then ClientDataSet1.First;
  Memo1.Clear;
  while not ClientDataSet1.Eof do
  begin
    Memo1.Lines.Add(ClientDataSet1.FieldList[0].Value);
    ClientDataSet1.Next;
  end;
  Memo1.Lines.Add('-------');

  for i := 1 to ClientDataSet1.RecordCount do
  begin
    ClientDataSet1.RecNo := i;
    Memo1.Lines.Add(ClientDataSet1.FieldList[1].Value);
  end;
end;

{ 通过 GetFieldList 可以读取几个指定字段的 TField 对象的列表 }
procedure TForm1.Button5Click(Sender: TObject);
var
  List: TList;
  Field: TField;
  i: Integer;
begin
  List := TList.Create;
  ClientDataSet1.GetFieldList(List, 'ACCT_NBR; SYMBOL; SHARES');

  Memo1.Clear;
  for i := 0 to List.Count - 1 do
  begin
    Field := List[i];
    Memo1.Lines.Add(Field.Value);
  end;

  List.Free;
end;

{ GetFieldData 读取字段值到指针 }
procedure TForm1.Button6Click(Sender: TObject);
var
  F1: Double;
  F2: array[0..7] of AnsiChar;
begin
  ClientDataSet1.GetFieldData(ClientDataSet1.Fields[0], @F1);
  ClientDataSet1.GetFieldData(ClientDataSet1.Fields[1], @F2);

  with Memo1.Lines do begin
    Clear;
    Add(FloatToStr(F1));
    Add(F2);
  end;
end;

//这是后面的例子用到的函数, 转换 TClientDataSet 时间格式到 TDateTime
function TDateTimeRecToDateTime(DataType: TFieldType; Data: TDateTimeRec): TDateTime;
var
  TimeStamp: TTimeStamp;
begin
  case DataType of
    ftDate:
      begin
        TimeStamp.Time := 0;
        TimeStamp.Date := Data.Date;
      end;
    ftTime:
      begin
        TimeStamp.Time := Data.Time;
        TimeStamp.Date := DateDelta;
      end;
  else
    try
      TimeStamp := MSecsToTimeStamp(Data.DateTime);
    except
      TimeStamp.Time := 0;
      TimeStamp.Date := 0;
    end;
  end;
  Result := TimeStampToDateTime(TimeStamp);
end;

{ GetCurrentRecord 是把当前行的所有字段(不包括 Blob 字段)读入到缓冲区 }
procedure TForm1.Button7Click(Sender: TObject);
type
  THoldingsStruct = packed record { 这是根据 holdings.xml 建立的数据结构 }
    ACCT_NBR: Double;
    SYMBOL: array[0..7] of AnsiChar; { 其 Size=7, 但后面还有个 #0 }
    SHARES: Double;
    PUR_PRICE: Double;
    PUR_DATE: Integer;
//    Other: array[0..4] of Byte; { 它后面还若干字节偏移, 测试时其字节数等于前面的字段数 }
  end;
var
  buf: THoldingsStruct;
  DateTimeRec: TDateTimeRec;
begin
  //ShowMessage(IntToStr(ClientDataSet1.RecordSize)); { 可通过这个值对照上面的结构 }
  if ClientDataSet1.GetCurrentRecord(@buf) then with Memo1.Lines do
  begin
    Clear;
    Add(FloatToStr(buf.ACCT_NBR));
    Add(buf.SYMBOL);
    Add(FloatToStr(buf.SHARES));
    Add(FloatToStr(buf.PUR_PRICE));

    DateTimeRec.Date := buf.PUR_DATE;
    Add(DateToStr(TDateTimeRecToDateTime(ftDate, DateTimeRec)));
  end;
end;
View Code

 



数据查找

  方法介绍

  1. Locate: 根据字段列表和对应的字段值查找并定位, 找到返回 True.
  2. Lookup: 根据字段列表和对应的字段值查找, 返回需要的字段值.
  3. SetKey、GotoKeySetKey、GotoNearest: 根据索引字段的值查找, 先切换状态再根据条件定位.
  4. FindKey FindNearest: 根据索引字段的值查找.

  其中的 GotoNearest、FindNearest 在找不到的情况下会定位到近似值

  测试代码:

//准备: 窗体上放一个 ClientDataSet1 和六个 Button

{ 准备测试数据 }
procedure TForm1.FormCreate(Sender: TObject);
begin
  with ClientDataSet1 do begin
    FieldDefs.Add('ID', ftInteger);
    FieldDefs.Add('Name', ftString, 6);
    FieldDefs.Add('Age', ftWord);
    CreateDataSet;
    AppendRecord([1, '赵AB', 11]);
    AppendRecord([2, '钱AB', 22]);
    AppendRecord([3, '孙AB', 33]);
    AppendRecord([4, '李AB', 44]);
    AppendRecord([5, '赵ab', 55]);
    AppendRecord([6, '钱ab', 66]);
    AppendRecord([7, '孙ab', 77]);
    AppendRecord([8, '李ab', 88]);
  end;
end;

{ Locate 测试 }
procedure TForm1.Button1Click(Sender: TObject);
begin
  if ClientDataSet1.Locate('Name', '赵ab', []) then
    ShowMessage(ClientDataSet1.FieldValues['Age']); { 55 }

  if ClientDataSet1.Locate('Name', '赵ab', [loCaseInsensitive]) then
    ShowMessage(ClientDataSet1.FieldValues['Age']); { 11 }

  if ClientDataSet1.Locate('Name', '钱a', [loPartialKey]) then
    ShowMessage(ClientDataSet1.FieldValues['Age']); { 66 }

  if ClientDataSet1.Locate('Name', '钱a', [loCaseInsensitive,loPartialKey]) then
    ShowMessage(ClientDataSet1.FieldValues['Age']); { 22 }

  if ClientDataSet1.Locate('Name;Age', VarArrayOf(['钱ab',66]), []) then
    ShowMessage(ClientDataSet1.FieldValues['Age']); { 66 }
end;

{ Lookup 测试 }
procedure TForm1.Button2Click(Sender: TObject);
var
  R: Variant;
  i: Integer;
begin
  R := ClientDataSet1.Lookup('Name', '钱AB', 'Age');
  if not VarIsNull(R) then ShowMessage(R); { 22 }

  R := ClientDataSet1.Lookup('Name;Age', VarArrayOf(['钱ab',66]), 'Age');
  if not VarIsNull(R) then ShowMessage(R); { 66 }

  R := ClientDataSet1.Lookup('ID', 6, 'Name;Age');
  if VarIsArray(R) then
    for i := VarArrayLowBound(R, 1) to VarArrayHighBound(R, 1) do
      ShowMessage(R[i]); { 钱ab / 66}
end;

{ SetKey、GotoKey 测试 }
procedure TForm1.Button3Click(Sender: TObject);
begin
  ClientDataSet1.IndexFieldNames := 'Name';
  ClientDataSet1.SetKey;
  ClientDataSet1.FieldValues['Name'] := '钱ab';
  if ClientDataSet1.GotoKey then
    ShowMessage(ClientDataSet1.FieldValues['Age']); { 66 }
end;

{ SetKey、GotoNearest 测试 }
procedure TForm1.Button4Click(Sender: TObject);
begin
  ClientDataSet1.IndexFieldNames := 'Name';
  ClientDataSet1.SetKey;
  ClientDataSet1.FieldValues['Name'] := '';
  ClientDataSet1.GotoNearest;
  ShowMessage(ClientDataSet1.FieldValues['Age']); { 77 }
end;

{ FindKey 测试 }
procedure  

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Matlab字符串相加发布时间:2022-07-18
下一篇:
matlab生成HEX文件-任意信号大于64K长度发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap