delphi - TJvCsvDataSet 和过滤器

标签 delphi jedi

在过滤 TJvCsvDataSet 中上传的 .csv 文件时,我遇到问题。 下面以MCVE来讲解

program Project3;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  JvCsvData,
  data.DB;

var
  FJvCsvDataSet: TJvCsvDataSet;
I:Integer;
begin
  ;
  FJvCsvDataSet := TJvCsvDataSet.Create(nil);
  FJvCsvDataSet.CsvFieldDef :=
    'VTHB:%,VTHS:%,VTHBBP:&,VTBBSP:&,VTHBLP:&,VTHBLS:&,VTHTS:@';
  FJvCsvDataSet.FieldDefs.Add('VTHB', ftInteger, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHS', ftInteger, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBBP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTBBSP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBLP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBLS', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHTS', ftDateTime, 0, False);

    FJvCsvDataSet.FileName :=
    'E:\...\abc.csv';
  FJvCsvDataSet.Open;
  FJvCsvDataSet.First;
//  FJvCsvDataSet.Sort('VTHB,VTHBBP', True);
  FJvCsvDataSet.Filtered := False;
  FJvCsvDataSet.Filter := '';
  for I := 1 to 1093 do
  begin
    FJvCsvDataSet.Filter:='VTHB=' + IntToStr(I);
    FJvCsvDataSet.Filtered := True;
  end;
  FJvCsvDataSet.Free;
end.

以下是FJvCsvDataSet上传的abc.csv样本

VTHB,VTHS,VTHBBP,VTBBSP,VTHBLP,VTHBLS,VTHTS
1,1,3.05,279.86,3.1,115.98,2019-08-10 14:28:47.505
1,2,3.9,259.65,3.95,237.73,2019-08-10 14:28:47.52
1,3,3.9,136.48,3.95,31.97,2019-08-10 14:28:47.52
1,5,10.5,68.83,11,52.03,2019-08-10 14:28:47.52
1,4,12.5,41.4,13,47.75,2019-08-10 14:28:47.52
2,1,3.05,279.86,3.1,115.98,2019-08-10 14:28:47.863
2,2,3.9,259.65,3.95,237.73,2019-08-10 14:28:47.863
2,3,3.9,136.48,3.95,31.97,2019-08-10 14:28:47.863
2,5,10.5,68.83,11,52.03,2019-08-10 14:28:47.863
2,4,12.5,41.4,13,47.75,2019-08-10 14:28:47.863

执行语句FJvCsvDataSet.Filter:='VTHB=' + IntToStr(I);时,FJvCsvDataSet.RecordCount不会改变,因此不执行过滤

我做错了什么?

最佳答案

我不认为你做任何“错误”的事情,只是 TJvCsvDataSet 似乎以一种相当奇怪的方式实现过滤。

使用您的代码设置并打开数据集,以下代码可以正常工作并生成预期的记录(在代码的 VCL 版本的 DBGrid 中观察到):

FJvCsvDataSet.SetFilterNum('VTHB', jfIntEqual, 1);
FJvCsvDataSet.Filtered := True;

这会导致 FJvCsvDataSet.RecordCount 为 5,正如它应该的那样。这种过滤方式使用以下枚举作为 SetFilterNum 的第二个参数:

TJvCsvFilterNumCompare = (jfIntEqual, jfIntNotEqual, jfLessThan, jfGreaterThan);

但是,这样做

FJvCsvDataSet.Filter:= 'VTHB=1';

产生不正确的结果,即没有记录被过滤掉,RecordCount为10。显然出了问题,我稍后会回来告诉你我是否发现了问题所在。

更新我进一步研究了一下,确实有一些东西 奇怪的事情发生了。

只是做

FJvCsvDataSet.Filter:= 'VTHB = 1';
FJvCsvDataSet.Filtered := True;

没有任何影响,数据集甚至不扫描记录以查看它们是否 匹配过滤器。 OTOH 正在这样做

FJvCsvDataSet.SetFilter('VTHB', '1');
FJvCsvDataSet.Filtered := True;

确实导致 SetFilter 方法开始扫描行

// string Filtering: Make Rows Visible Only if they match filterString
procedure TJvCustomCsvDataSet.SetFilter(const FieldName: string; Pattern: string);

行是否被正确标记为“已过滤”,具体取决于它们是否与过滤器匹配。 然而,至少有两件奇怪的事情:

  • 所有记录,无论匹配与否,仍然由网格显示。我认为这 意味着问题出在其他地方,可能与 InternalSkipFiltered 方法有关, 但是为什么 FJvCsvDataSet.SetFilterNum('VTHB', jfIntEqual, 1) 有效呢? 需要进一步探索。

  • 应用过滤器后对数据集调用 Close 和 Open 不会导致 按逻辑应该重新扫描行,但我们不会调用 SetFilter 第二次,所以这大概是WAD。但这是一个奇怪的设计,因为 SeFilter 首先不应公开访问,在我看来,它应该由 Filter 属性的 setter 调用。

更新#2好吧,我们不能说我们没有收到警告

https://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvCustomCsvDataSet.SetFilter

Note that this feature is NOT API-compatible with or similar to the filtering feature that is normally found in VCL TTable component.

前面的描述是根据将字段过滤为字符数据来表达的,所以我想知道它是否曾经打算处理 ftInteger 字段....

关于delphi - TJvCsvDataSet 和过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61973696/

相关文章:

delphi - 如何阻止 TJvSearchFiles 进行递归连接?

delphi - 如何使用 WinInet 在 Delphi 2010 中发送 HTTP Post 请求

windows - 关于 JvPatchFile 组件?

delphi - 类助手不会覆盖祖先的虚拟方法

delphi - 如何为 firemonkey TForm OnKeyDown 事件 : 分配快捷键

delphi - 最新 7z.dll 的 JEDI JclCompression 提取问题

delphi - TJclStringList 在 Free 上崩溃

delphi - JEDI JCL 压缩库无法打开跨区存档文件

delphi - 解决网络快捷方式

delphi - 是否可以将动画图标与 VirtualTreeView 节点一起使用?