要するに、私はデルファイに不慣れであり、次のことを達成したいと思っています。
- テーブルの定義は.cdsファイル{インデックス、データ、日付}で、一部のデータは.csv形式です。
- .csvファイルをテーブルにロードし、その変更とエラーをログに表示したい(例:無効な日付形式)。
質問
このタスクをエレガントに解決するにはどうすればよいですか?
.csv から 1 行ずつ読み取り、各行を StringList の 'DelimitedText' に設定し、レコードをデータセットに追加し、文字列リストをループして各フィールドの値を設定してから、データセットに投稿できます。
「フィールド値の割り当て」/「投稿」を try-except ブロックに配置し、発生した例外のエラー メッセージを好きな情報 (たとえば、不正な形式のフィールド値/名前、行番号、および/または行全体など) と一緒にログに記録できます。 ) ファイル fi へ
(「変更」の意味がわかりません。私が理解したことから、.csv の行がデータセットに挿入されるため、すべての変更が挿入されます。)
編集:具体的なことについて議論できるようにする(タスクを把握するのに苦労しています:))
サンプル データ (CodeGear サンプル 'Clients.cds' の一部):
Davis;Jennifer;1023495,0000;100 Cranberry St.;Wellesley;MA;02181;516-292-3945;01.01.93 Jones;Arthur;2094056,0000;10 Hunnewell St;Los Altos;CA;94024;415-941 -4321;07.02.81 Parker;Debra;1209395,0000;74 South St;Atherton;CA;98765;916-213-2234;23.10.90 Sawyer;Dave;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;
JvCsvDataSet (JEDI JVCL コンポーネント) は CSV ファイルを適切に解析するため、データ ポンプ コンポーネントを使用してデータをクライアント データセットに移動し、いくつかの検証を行います。
しかし、CSV ファイルをデータベース対応コントロールに提供するだけで本当に必要な場合は、ClientDataSet を完全に除外し、目的のために構築されたコンポーネントを使用するだけです。ネジを釘にしたり、釘をネジにしたりしないでください。どちらも金属製ですが、役割が異なります。
CSV ファイル テーブル定義は、目的が CDS テーブル定義とはまったく異なります。JvCsvDataSet は、メタデータ (整数、文字列、日時などのフィールド データ型、および関連するフィールド名、ヘッダー行がない CSV ファイルの場合)、ClientDatSet で行うよりも簡単です。
私の知る限り、.csv データを .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
パッケージをビルドしてインストールし、テスト アプリをコンパイルして実行できます。テスト アプリのソースには、使用方法がよく示されています。
データベースが DBISAM である可能性が低い場合は、単純に IMPORT SQL ステートメントを使用できます。
import table "tablename" from "myinputfile.csv" Delimiter ',';
他のデータベースにも同様の機能がある場合があります。