Восстановление набора данных из файла значений, разделенных разделителем - PullRequest
1 голос
/ 17 июня 2011

Короче говоря, я новичок в Delphi и хочу добиться следующего:

  • У меня есть определение таблицы в виде файла .cds {индекс, данные, дата} и некоторые данные в формате .csv.
  • Я хочу загрузить файл .csv в таблицу и показать в журнале его изменения и ошибки (например, недопустимый формат даты).

Вопрос

Как решить эту задачу элегантно?

Ответы [ 4 ]

3 голосов
/ 21 июня 2011

Вы можете читать построчно из .csv, устанавливать для каждой строки значение DelimitedText из StringList, добавлять запись в набор данных, циклически перебирать список строк, чтобы установить значение каждого поля, а затем отправлять данные в набор данных.Вы можете поместить 'значение поля assinging' / 'posting' в блок try-кроме и зарегистрировать любое сообщение об ошибке вызванных исключений вместе с информацией, которая вам нравится (например, искаженное значение / имя поля, номер строки и / или вся строка и т. Д.).) в файл fi

(я не понимаю, что вы подразумеваете под «изменениями», из того, что я понял, строки из .csv будут вставлены в набор данных, следовательно, все изменения будут вставлены.)

edit : чтобы иметь возможность обсуждать что-то конкретное (мне трудно понять задачу:))

Пример данных (часть примера CodeGear 'Clients.cds'):

Дэвис; Дженнифер; 1023495,0000; 100 Cranberry St.; Wellesley; MA; 02181; 516-292-3945; 01.01.93 Джонс; Артур; 2094056,0000; 10 Hunnewell St; LosAltos; CA; 94024; 415-941-4321; 07.02.81 Parker; Дебра; 1209395,0000; 74 South St; Atherton; CA; 98765; 916-213-2234; 23.10.90 Сойер; Дейв; 3094095,0000;101 Oakland St; Los Altos; CA; 94022; 415-948-9998; 21.12.89 White; Cindy; 1024034,0000; 1 Wentworth Dr; Los Altos; CA; 94022; 415-948-6547; 01.10.92

procedure TForm1.FormCreate(Sender: TObject);
begin
  CDS.FieldDefs.Add('LAST_NAME', ftString, 20);
  CDS.FieldDefs.Add('FIRST_NAME', ftString, 20);
  CDS.FieldDefs.Add('ACCT_NBR', ftInteger);
  CDS.FieldDefs.Add('ADDRESS_1', ftString, 30);
  CDS.FieldDefs.Add('CITY', ftString, 15);
  CDS.FieldDefs.Add('STATE', ftString, 2);
  CDS.FieldDefs.Add('ZIP', ftString, 5);
  CDS.FieldDefs.Add('TELEPHONE', ftString, 12);
  CDS.FieldDefs.Add('DATE_OPEN', ftDate);
  CDS.CreateDataSet;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  csv: TextFile;
  Rec: string;
  Fields: TStringList;
  LineNo: Integer;
  i: Integer;
begin
  Fields := TStringList.Create;
  try
    Fields.StrictDelimiter := True;
    Fields.Delimiter := ';';

    AssignFile(csv, ExtractFilePath(Application.ExeName) + 'clients.csv');
    try
      Reset(csv);

      LineNo := 0;
      while not Eof(csv) do begin
        Inc(LineNo);
        Readln(csv, Rec);

        Fields.DelimitedText := Rec;
        CDS.Append;

        for i := 0 to Fields.Count - 1 do
          try
            CDS.Fields[i].Value := Fields[i];   // Variant conversion will raise
                                 // exception where conversion from string fails
          except
            on E:EDatabaseError do begin
              CDS.Cancel;        // Failed, discard the record

              // log the error instead of showing a message
              ShowMessage(Format('Cannot set field "%s" at line %d' + sLineBreak +
                  'Error: %s', [CDS.Fields[i].FieldName, LineNo, E.Message]));
              Break;             // Continue with next record
            end;
          end;

        if CDS.State = dsInsert then // It's not dsInsert if we Cancelled the Insert
          try
            CDS.Post;
          except
            on E:EDatabaseError do begin
              // log error instead of showing
              ShowMessage(Format('Cannot post line %d' + sLineBreak + 'Error: %s',
                  [LineNo, E.Message]));
              CDS.Cancel;
            end;
          end;

      end;
    finally
      CloseFile(csv);
    end;
  finally
    Fields.Free;
  end;
end;

procedure TForm1.CDSBeforePost(DataSet: TDataSet);
begin
  // Superficial posting error
  if CDS.FieldByName('LAST_NAME').AsString = '' then
    raise EDatabaseError.Create('LAST_NAME cannot be empty');
end;
3 голосов
/ 21 июня 2011

Я бы использовал JvCsvDataSet (JEDI-компонент JEDI), потому что он правильно анализирует CSV-файлы, а затем использует компонент «Насос данных» для перемещения данных в набор данных клиента вместе с некоторой проверкой.

Но есливсе, что вам действительно нужно сделать, это предоставить файл CSV элементу управления с учетом данных, я бы полностью исключил ClientDataSet и просто использовал компонент, созданный для той цели, которую вы пытаетесь сделать.Не используйте винт как гвоздь или гвоздь как винт.Они оба сделаны из металла, но выполняют разные задачи.

Определения таблиц файлов CSV весьма различны по назначению, чем определения таблиц CDS, а JvCsvDataSet предоставляет простое строковое свойство, которое можно настроить для предоставленияметаданные (типы данных поля, такие как целое число или строка или дата-время, и связанные имена полей для файлов CSV, в которых отсутствует строка заголовка) проще, чем вы могли бы надеяться сделать это в ClientDatSet.

2 голосов
/ 21 июня 2011

AFAIK, нет прямого способа загрузить данные .csv в TClientDataset.

Самый простой способ, о котором я могу подумать, это использовать TTextDataSet (найденный в Demos\Delphi\Database\TextData, доступный изStart->All Programs->Embarcadero RAD Studio XE->Samples).Вы можете использовать его так же, как любой другой TDataSet, то есть вы можете читать из него Fields или использовать FieldByName, и он поддерживает Bof, Eof, Next и Prior.

Вы можете просто выполнить итерацию и попытаться присвоить своим столбцам CDS, и это приведет к ошибкам, которые вы затем сможете обработать или зарегистрировать.

Вы можете установить TTextDataset как любой другой компонент или просто добавить модуль впредложение uses и создайте его во время выполнения.В папке есть файл readme.htm, который мало что объясняет;ключевые свойства FileName и Active.:)

Включает в себя как предварительно разработанный пакет (TextPkg.dproj), так и тестовое приложение (TextTest.dproj).Также есть группа проектов (TextDataGroup.groupproj) - вы можете просто открыть ее в IDE, собрать и установить пакет TextPkg, а затем скомпилировать и запустить тестовое приложение.Источник для тестового приложения хорошо показывает использование.

1 голос
/ 21 июня 2011

В случае, если вашей базой данных является DBISAM, вы можете просто использовать оператор IMPORT SQL.

import table "tablename" from "myinputfile.csv" Delimiter ',';

Другие базы данных могут иметь аналогичную функцию.

...