#csv #delphi #import #interbase #delphi-10.1-berlin
#csv #delphi #импорт #interbase #delphi-10.1-берлин
Вопрос:
Я запускаю свое первое приложение, которому требуется встроенная база данных, возможность импортировать CSV в таблицу и отображать результаты в виде таблицы. Я использовал мастер привязки в реальном времени, чтобы связать свою сетку с 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;
1-я проблема, это очень медленный процесс импорта файла с общим количеством столбцов 7 и общим количеством строк или записей 5500 в файле. Я настраиваю свой FDBatchMoveTextReader для файла CSV, добавляя поля файла. Я настроил свой FDBatchMoveDataSetWriter для записи в Dataset fdtablet Task и присвоил ему поля моей таблицы.
Вот мой базовый код:
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. Мало того, что это занимает много времени, но я заменяю данные в таблице fdtablet task, задав FDBatchMove1 .Параметры для [poClearDest,poIdentityInsert].
Процесс идет медленно, и сетка никогда не заполняется новыми данными файла, пока я не закрою и не открою приложение снова. Как я могу ускорить этот процесс и отобразить новые данные в таблице после завершения процесса?
Ответ №1:
Обновление С учетом ваших комментариев я обновил это в третий раз, чтобы показать пример, который настолько близок, насколько я готов добраться до вашего кода, и который, похоже, не страдает от проблем, о которых вы говорите. у вас есть. Я могу только предложить вам попробовать это самостоятельно, а затем попытаться определить, почему ваш собственный проект не ведет себя так же. Я не собираюсь больше тратить на это время.
Использование динамических привязок намного медленнее, чем использование традиционных компонентов с поддержкой БД.
Тем не менее, боюсь, я не могу воспроизвести ваши проблемы. Я настроил проект FMX с несколькими устройствами, как показано в приведенном ниже коде и выдержке DFM. Чтобы сделать его как можно более автономным, я поместил все компоненты и код в единый модуль формы, и код генерирует CSV-файл для импорта.
Как вы увидите, если вы скомпилируете и запустите проект, приложение запускается со строковой сеткой, содержащей 3 строки, и нажатие кнопки ImportCSV генерирует и импортирует 9997 дополнительных строк. На моем ноутбуке это занимает не более пары секунд.
Обратите внимание, что я не вижу никаких заметных изменений в скорости ImportCSV
процедуры, если я закомментирую вызовы DisableControls и EnableControls . Это меня немного удивило, но, возможно, TFDBatchMove делает это или подобное внутренне.
В этом примере приложения показана особенность LiveBindings (по крайней мере, в Сиэтле). Без вызовов FDMemTable1.First
in FormCreate
и ImportCSV
StringGrid показывает только строку 3 после FormCreate
и строки 1, 2 и 10000 после 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:tempbook1.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:tempData.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
Комментарии:
1. Спасибо за ваш ответ, и я попробую сегодня утром. Я действительно скучаю по DBISAM только с компонентами базы данных std, такими как таблицы и исходные компоненты, но мне нужен встроенный компонент database engine, который будет работать как на Windows, так и на OSX, и Embarcadero рекомендовал мне использовать FireDAC с IB (IBLite).
2. ОК. Это намного быстрее, но сетка никогда не заполняется заново. Я должен был упомянуть, поскольку я перехожу из Delphi5, я помещаю все свои компоненты данных в форму, которую я назвал Datamodule1. Сетка находится в основной форме, и мастер Live Designer по завершении создал список привязок в основной форме. вот мой текущий код:
3. процедура TMainForm.MenuItem2Click(отправитель: TObject); начать с DataModule начать попробуйте BindSourceDB1.DataSet := Nil; fdtablet task.DisableControls; если OpenDialog1. Выполнить, затем начать ShowMessage(‘Начать чтение’); FDBatchMoveTextReader1.FileName := OpenDialog1. FileName; ShowMessage(‘Начать перемещение’); FDBatchMove1. Выполнить; Завершить; Наконец fdtablet task.EnableControls; BindSourceDB1.DataSet := fdtablet task; Показать сообщение (‘готово’); конец; конец; конец;
4. Пожалуйста, будьте более осторожны. В одном комментарии вы говорите, что ваша «форма» называется «Datamodule 1 «, но в следующем комментарии вы пишете «С помощью DataModule». Что это? В любом случае, ваш Datamodule1 действительно потомок TForm или TDataModule? Это большая разница, и потомки TDataModule не могут содержать визуальные компоненты, такие как сетки.
5. Кстати, я постараюсь добавить полный пример кода к своему ответу позже этим вечером, примерно через пару часов.