在过滤 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/