Импорт CSV-файла с помощью FDBatchMove в fdtablet task

#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. Кстати, я постараюсь добавить полный пример кода к своему ответу позже этим вечером, примерно через пару часов.