使用 FDBatchMove 将 CSV 文件导入 FDTableTask
Importing a CSV file using a FDBatchMove into a FDTableTask
我正在开始我的第一个应用程序,它需要一个嵌入式数据库,能够将 CSV 导入 table 并将结果显示到网格中。我使用实时绑定向导 link 我的网格到 BindSourceDB。以下是我使用的基本组件:
BindingsList1: TBindingsList;
LinkFillControlToField1: TLinkFillControlToField;
BindSourceDB1: TBindSourceDB;
FireTaskList: TFDConnection;
FDTableTask: TFDTable;
FDQuery: TFDQuery;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDPhysIBDriverLink1: TFDPhysIBDriverLink;
FDTableTaskDATE: TDateField;
FDTableTaskDESCRIPTION: TStringField;
FDTableTaskORIGDESC: TStringField;
FDTableTaskAMOUNT: TIntegerField;
FDTableTaskTYPE: TStringField;
FDTableTaskCATEGORY: TStringField;
FDTableTaskACCTNAME: TStringField;
FDTableTaskLABELS: TStringField;
FDTableTaskNOTES: TMemoField;
FDBatchMove1: TFDBatchMove;
FDBatchMoveTextReader1: TFDBatchMoveTextReader;
FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter;
OpenDialog1: TOpenDialog;
Grid1: TGrid;
LinkGridToDataSourceBindSourceDB1: TLinkGridToDataSource;
第一个问题,导入一个总共有 7 列且文件中总共有 5500 行或记录的文件是一个非常缓慢的过程。我为 CSV 文件设置了我的 FDBatchMoveTextReader,添加了文件的字段。我将我的 FDBatchMoveDataSetWriter 设置为写入数据集 FDTableTask 并将我的 table 字段分配给它。
这是我的基本代码:
if OpenDialog1.Execute then
begin
ShowMessage('Start read'); // more then 5 secods before this displays (sometimes)
FDBatchMoveTextReader1.FileName := OpenDialog1.FileName;
ShowMessage('Start Move'); // Dispalys instantly
FDBatchMove1.Execute;
Showmessage('done'); //About 25 seconds before this displays
end;
它有效,但需要很长时间。在 Delphi 5 中执行此操作并使用 DBISAM 和 CSV 导入组件,整个过程大约需要 5 秒。我只有 FDBatchMove 组件的默认设置。不仅需要很长时间,而且我通过将 FDBatchMove1.Options 设置为 [poClearDest,poIdentityInsert].
来替换 FDTableTask table 中的数据
这个过程很慢,在我关闭并重新打开应用程序之前,网格永远不会重新填充新文件数据。如何加快此过程并在过程完成后在网格中显示新数据?
更新 鉴于您的评论,我已经第三次更新了它以显示一个与我准备获取您的代码最接近的示例,并且似乎没有遇到您所说的问题。我只能建议你自己尝试,然后尝试确定你自己的原因
项目的行为方式不同。我不会再花钱了
有时间了。
使用 Live Bindings 比使用传统的 db-aware 组件慢。
也就是说,恐怕我无法重现您的问题。我设置了一个多设备 FMX
项目如下面的代码和 DFM 摘录所示。让它成为
尽可能独立,我把所有的组件和代码放在一个单一的
表单单元和代码生成要导入的 CSV 文件。
正如您编译和 运行 项目时看到的那样,应用程序以
包含 3 行的 StringGrid,单击 ImportCSV 按钮生成和
导入 9997 个额外行。这对我来说只需要几秒钟
笔记本电脑。
请注意,我没有看到 ImportCSV
的速度有任何明显变化
过程,如果我注释掉对 DisableControls 和 EnableControls 的调用。这个
有点让我吃惊,但也许 TFDBatchMove 在内部做了这个或类似的事情。
此示例应用程序显示了 LiveBindings 的一个怪癖(至少在西雅图)。没有
在 FormCreate
和 ImportCSV
中调用 FDMemTable1.First
,StringGrid
仅显示 FormCreate
之后的第 3 行和 ImportCSV
.
之后的第 1、2 和 10000 行
代码:
type
TForm1 = class(TForm)
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
StringGrid1: TStringGrid;
BindSourceDB1: TBindSourceDB;
BindingsList1: TBindingsList;
FDMemTable1: TFDMemTable;
FDMemTable1ID: TIntegerField;
FDMemTable1Name: TStringField;
LinkGridToDataSource1: TLinkGridToDataSource;
FDBatchMove1: TFDBatchMove;
FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter;
Button1: TButton;
BindNavigator1: TBindNavigator;
FDBatchMoveTextReader1: TFDBatchMoveTextReader;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure ImportCSV;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
begin
ImportCSV;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FDMemTable1.IndexFieldNames := 'ID';
FDMemTable1.CreateDataSet;
FDMemTable1.InsertRecord([1, 'One']);
FDMemTable1.InsertRecord([2, 'Two']);
FDMemTable1.InsertRecord([3, 'Three']);
FDMemTable1.First;
end;
procedure TForm1.ImportCSV;
var
AFileName : String;
TL : TStringList;
i : Integer;
begin
AFileName := 'c:\temp\book1.csv';
try
TL := TStringList.Create;
for i := 4 to 10000 do
TL.Add(IntToStr(i) + ',' + 'Row ' + IntToStr(i));
TL.SaveToFile(AFileName);
FDMemTable1.DisableControls;
FDBatchMoveTextReader1.FileName := AFileName;
FDBatchMove1.Execute;
FDMemTable1.First;
finally
FDMemTable1.EnableControls;
TL.Free;
end;
end;
DFM
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 480
ClientWidth = 429
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnCreate = FormCreate
DesignerMasterStyle = 0
object StringGrid1: TStringGrid
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 409.000000000000000000
Size.Height = 201.000000000000000000
Size.PlatformDefault = False
TabOrder = 3
RowCount = 100
RowHeight = 21.000000000000000000
Viewport.Width = 389.000000000000000000
Viewport.Height = 176.000000000000000000
end
object Button1: TButton
Position.X = 160.000000000000000000
Position.Y = 288.000000000000000000
TabOrder = 10
Text = 'Button1'
OnClick = Button1Click
end
object BindNavigator1: TBindNavigator
Position.X = 8.000000000000000000
Position.Y = 216.000000000000000000
Size.Width = 240.000000000000000000
Size.Height = 25.000000000000000000
Size.PlatformDefault = False
TabOrder = 19
DataSource = BindSourceDB1
xRadius = 4.000000000000000000
yRadius = 4.000000000000000000
end
object FDGUIxWaitCursor1: TFDGUIxWaitCursor
Provider = 'FMX'
Left = 352
Top = 48
end
object BindSourceDB1: TBindSourceDB
DataSet = FDMemTable1
ScopeMappings = <>
Left = 160
Top = 48
end
object BindingsList1: TBindingsList
Methods = <>
OutputConverters = <>
Left = 272
Top = 48
object LinkGridToDataSource1: TLinkGridToDataSource
Category = 'Quick Bindings'
DataSource = BindSourceDB1
GridControl = StringGrid1
Columns = <>
end
end
object FDMemTable1: TFDMemTable
FetchOptions.AssignedValues = [evMode]
FetchOptions.Mode = fmAll
ResourceOptions.AssignedValues = [rvSilentMode]
ResourceOptions.SilentMode = True
UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True
Left = 72
Top = 48
object FDMemTable1ID: TIntegerField
FieldName = 'ID'
end
object FDMemTable1Name: TStringField
FieldName = 'Name'
end
end
object FDBatchMove1: TFDBatchMove
Reader = FDBatchMoveTextReader1
Writer = FDBatchMoveDataSetWriter1
Mappings = <>
LogFileName = 'c:\temp\Data.log'
Left = 72
Top = 136
end
object FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter
DataSet = FDMemTable1
Left = 352
Top = 136
end
object FDBatchMoveTextReader1: TFDBatchMoveTextReader
DataDef.Fields = <>
Left = 192
Top = 136
end
end
我正在开始我的第一个应用程序,它需要一个嵌入式数据库,能够将 CSV 导入 table 并将结果显示到网格中。我使用实时绑定向导 link 我的网格到 BindSourceDB。以下是我使用的基本组件:
BindingsList1: TBindingsList;
LinkFillControlToField1: TLinkFillControlToField;
BindSourceDB1: TBindSourceDB;
FireTaskList: TFDConnection;
FDTableTask: TFDTable;
FDQuery: TFDQuery;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDPhysIBDriverLink1: TFDPhysIBDriverLink;
FDTableTaskDATE: TDateField;
FDTableTaskDESCRIPTION: TStringField;
FDTableTaskORIGDESC: TStringField;
FDTableTaskAMOUNT: TIntegerField;
FDTableTaskTYPE: TStringField;
FDTableTaskCATEGORY: TStringField;
FDTableTaskACCTNAME: TStringField;
FDTableTaskLABELS: TStringField;
FDTableTaskNOTES: TMemoField;
FDBatchMove1: TFDBatchMove;
FDBatchMoveTextReader1: TFDBatchMoveTextReader;
FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter;
OpenDialog1: TOpenDialog;
Grid1: TGrid;
LinkGridToDataSourceBindSourceDB1: TLinkGridToDataSource;
第一个问题,导入一个总共有 7 列且文件中总共有 5500 行或记录的文件是一个非常缓慢的过程。我为 CSV 文件设置了我的 FDBatchMoveTextReader,添加了文件的字段。我将我的 FDBatchMoveDataSetWriter 设置为写入数据集 FDTableTask 并将我的 table 字段分配给它。
这是我的基本代码:
if OpenDialog1.Execute then
begin
ShowMessage('Start read'); // more then 5 secods before this displays (sometimes)
FDBatchMoveTextReader1.FileName := OpenDialog1.FileName;
ShowMessage('Start Move'); // Dispalys instantly
FDBatchMove1.Execute;
Showmessage('done'); //About 25 seconds before this displays
end;
它有效,但需要很长时间。在 Delphi 5 中执行此操作并使用 DBISAM 和 CSV 导入组件,整个过程大约需要 5 秒。我只有 FDBatchMove 组件的默认设置。不仅需要很长时间,而且我通过将 FDBatchMove1.Options 设置为 [poClearDest,poIdentityInsert].
来替换 FDTableTask table 中的数据这个过程很慢,在我关闭并重新打开应用程序之前,网格永远不会重新填充新文件数据。如何加快此过程并在过程完成后在网格中显示新数据?
更新 鉴于您的评论,我已经第三次更新了它以显示一个与我准备获取您的代码最接近的示例,并且似乎没有遇到您所说的问题。我只能建议你自己尝试,然后尝试确定你自己的原因 项目的行为方式不同。我不会再花钱了 有时间了。
使用 Live Bindings 比使用传统的 db-aware 组件慢。
也就是说,恐怕我无法重现您的问题。我设置了一个多设备 FMX 项目如下面的代码和 DFM 摘录所示。让它成为 尽可能独立,我把所有的组件和代码放在一个单一的 表单单元和代码生成要导入的 CSV 文件。
正如您编译和 运行 项目时看到的那样,应用程序以 包含 3 行的 StringGrid,单击 ImportCSV 按钮生成和 导入 9997 个额外行。这对我来说只需要几秒钟 笔记本电脑。
请注意,我没有看到 ImportCSV
的速度有任何明显变化
过程,如果我注释掉对 DisableControls 和 EnableControls 的调用。这个
有点让我吃惊,但也许 TFDBatchMove 在内部做了这个或类似的事情。
此示例应用程序显示了 LiveBindings 的一个怪癖(至少在西雅图)。没有
在 FormCreate
和 ImportCSV
中调用 FDMemTable1.First
,StringGrid
仅显示 FormCreate
之后的第 3 行和 ImportCSV
.
代码:
type
TForm1 = class(TForm)
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
StringGrid1: TStringGrid;
BindSourceDB1: TBindSourceDB;
BindingsList1: TBindingsList;
FDMemTable1: TFDMemTable;
FDMemTable1ID: TIntegerField;
FDMemTable1Name: TStringField;
LinkGridToDataSource1: TLinkGridToDataSource;
FDBatchMove1: TFDBatchMove;
FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter;
Button1: TButton;
BindNavigator1: TBindNavigator;
FDBatchMoveTextReader1: TFDBatchMoveTextReader;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure ImportCSV;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
begin
ImportCSV;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FDMemTable1.IndexFieldNames := 'ID';
FDMemTable1.CreateDataSet;
FDMemTable1.InsertRecord([1, 'One']);
FDMemTable1.InsertRecord([2, 'Two']);
FDMemTable1.InsertRecord([3, 'Three']);
FDMemTable1.First;
end;
procedure TForm1.ImportCSV;
var
AFileName : String;
TL : TStringList;
i : Integer;
begin
AFileName := 'c:\temp\book1.csv';
try
TL := TStringList.Create;
for i := 4 to 10000 do
TL.Add(IntToStr(i) + ',' + 'Row ' + IntToStr(i));
TL.SaveToFile(AFileName);
FDMemTable1.DisableControls;
FDBatchMoveTextReader1.FileName := AFileName;
FDBatchMove1.Execute;
FDMemTable1.First;
finally
FDMemTable1.EnableControls;
TL.Free;
end;
end;
DFM
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 480
ClientWidth = 429
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnCreate = FormCreate
DesignerMasterStyle = 0
object StringGrid1: TStringGrid
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 409.000000000000000000
Size.Height = 201.000000000000000000
Size.PlatformDefault = False
TabOrder = 3
RowCount = 100
RowHeight = 21.000000000000000000
Viewport.Width = 389.000000000000000000
Viewport.Height = 176.000000000000000000
end
object Button1: TButton
Position.X = 160.000000000000000000
Position.Y = 288.000000000000000000
TabOrder = 10
Text = 'Button1'
OnClick = Button1Click
end
object BindNavigator1: TBindNavigator
Position.X = 8.000000000000000000
Position.Y = 216.000000000000000000
Size.Width = 240.000000000000000000
Size.Height = 25.000000000000000000
Size.PlatformDefault = False
TabOrder = 19
DataSource = BindSourceDB1
xRadius = 4.000000000000000000
yRadius = 4.000000000000000000
end
object FDGUIxWaitCursor1: TFDGUIxWaitCursor
Provider = 'FMX'
Left = 352
Top = 48
end
object BindSourceDB1: TBindSourceDB
DataSet = FDMemTable1
ScopeMappings = <>
Left = 160
Top = 48
end
object BindingsList1: TBindingsList
Methods = <>
OutputConverters = <>
Left = 272
Top = 48
object LinkGridToDataSource1: TLinkGridToDataSource
Category = 'Quick Bindings'
DataSource = BindSourceDB1
GridControl = StringGrid1
Columns = <>
end
end
object FDMemTable1: TFDMemTable
FetchOptions.AssignedValues = [evMode]
FetchOptions.Mode = fmAll
ResourceOptions.AssignedValues = [rvSilentMode]
ResourceOptions.SilentMode = True
UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True
Left = 72
Top = 48
object FDMemTable1ID: TIntegerField
FieldName = 'ID'
end
object FDMemTable1Name: TStringField
FieldName = 'Name'
end
end
object FDBatchMove1: TFDBatchMove
Reader = FDBatchMoveTextReader1
Writer = FDBatchMoveDataSetWriter1
Mappings = <>
LogFileName = 'c:\temp\Data.log'
Left = 72
Top = 136
end
object FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter
DataSet = FDMemTable1
Left = 352
Top = 136
end
object FDBatchMoveTextReader1: TFDBatchMoveTextReader
DataDef.Fields = <>
Left = 192
Top = 136
end
end