Ich frage hier weil ggf jemand eine bessere Idee hat und sag schon mal Danke für eine andere Idee.
Hier ist eine (text)-Datei die ich in einer SQlite Tabelle importieren will.
Das ist eine sog. ADI / ADIF Datei. (benutzt im Amateurfunk).
Unten gebe ich den Header und die 2 Records . Die Records beginnen nach dem <EOH> (der Header ist nicht interessant) mit "<app_qrzlog_logid:" und ein Record ist beendet mit "<eor>", dann kommt der nächste..
Als alter dbf Benutzer würde das in eine Stringlist einfügen, dann Records aus dem bilden, dh vom Beginn bis zum Ende einen Record.
Dann aus diesen Records die Daten in einzelne Felder umfüllen.
Ich möchte es diesmal aber in SQLite haben (da ich eben in das eingestiegen bin und damit Erfahrung sammeln will)
Weil dann mit select die erforderlichen Daten gut extrahiert werden können wie zB wieviele verschiedene DXCC, band, gridsquare etc.
Doch es soll eine Apllikation werde die wir in userem Club einsetzen.
Weiter in Gedanken:
Würde, da man nicht alle Felder braucht eine FeldListe für den Import und eine FeldListe für die SQLIte db machen, auch damit die selects standardisiert sind (da nicht jeder SQL kann).
zB <band: --> BAND, <gridsquare: --> HIS_GRID, <my_gridsquare: --> MY_GRID etc (aus den GRID's kann man die Distanz rechnen)
QRZLogbook download for hb9fih
Date: Fri Jul 29 06:26:46 2022
Bookid: 19332
Records: 204
<ADIF_VER:5>3.1.1
<PROGRAMID:10>QRZLogbook
<PROGRAMVERSION:3>2.0
<eoh>
<app_qrzlog_logid:9>717291809
<app_qrzlog_qsldate:8>20220214
<app_qrzlog_status:1>C
<band:3>20m
<band_rx:3>20m
<call:5>9K2YD
<comment:9>QTH EA8 -
<cont:2>AS
<country:6>Kuwait
<cqz:2>21
<distance:4>6363
<dxcc:3>348
<email:23>sailor2251970@gmail.com
<eqsl_qsl_rcvd:1>N
<eqsl_qsl_sent:1>N
<freq:6>14.074
<freq_rx:6>14.074
<gridsquare:8>LL49AH17
<ituz:2>39
<lat:11>N029 19.483
<lon:11>E048 00.615
<lotw_qsl_rcvd:1>N
<lotw_qsl_sent:1>N
<mode:3>FT8
<my_city:3>EA8
<my_country:11>Switzerland
<my_cq_zone:2>14
<my_gridsquare:6>IL07xs
<my_itu_zone:2>28
<my_lat:11>N027 46.248
<my_lon:11>W018 02.520
<my_name:12>Erich Rieder
<name:22>Younes M H H ALMATROOK
<qrzcom_qso_upload_date:8>20220115
<qrzcom_qso_upload_status:1>Y
<qsl_rcvd:1>N
<qsl_sent:1>N
<qso_date:8>20220107
<qso_date_off:8>20220107
<qth:7>ALSHAAB
<rst_rcvd:3>599
<rst_sent:3>599
<station_callsign:6>HB9FIH
<time_off:4>1550
<time_on:4>1550
<tx_pwr:2>15
<eor>
<app_qrzlog_logid:9>722339967
<app_qrzlog_qsldate:8>20220214
<app_qrzlog_status:1>C
<band:3>40m
<band_rx:3>40m
<call:5>SP8LM
<comment:10>QTH EA8 -
<cont:2>EU
<country:6>Poland
<cqz:2>15
<distance:4>1042
<dxcc:3>269
<email:11>sp8lm@wp.pl
<eqsl_qsl_rcvd:1>N
<eqsl_qsl_sent:1>N
<freq:5>7.076
<freq_rx:5>7.076
<gridsquare:6>KN19FI
<ituz:2>28
<lat:11>N049 22.233
<lon:11>E022 25.167
<lotw_qsl_rcvd:1>N
<lotw_qsl_sent:1>N
<mode:4>JT65
<my_city:15>8820 Wädenswil
<my_country:11>Switzerland
<my_cq_zone:2>14
<my_gridsquare:6>JN47if
<my_itu_zone:2>28
<my_lat:11>N047 14.100
<my_lon:11>E008 40.933
<my_name:12>Erich Rieder
<name:21>Marek Jan Åagowski
<qrzcom_qso_upload_date:8>20220129
<qrzcom_qso_upload_status:1>Y
<qsl_rcvd:1>N
<qsl_sent:1>N
<qso_date:8>20220127
<qso_date_off:8>20220127
<qth:12>PolaÅczyk
<rst_rcvd:3>599
<rst_sent:3>599
<station_callsign:6>HB9FIH
<time_off:4>2105
<time_on:4>2105
<tx_pwr:2>20
<eor>
Import eines "wilden" Textfiles in SQLite
- af0815
- Lazarusforum e. V.
- Beiträge: 6770
- Registriert: So 7. Jan 2007, 10:20
- OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
- CPU-Target: 32Bit (64Bit)
- Wohnort: Burgenland
- Kontaktdaten:
Re: Import eines "wilden" Textfiles in SQLite
Ich würde das ganze Zeilenweise parsen den Header auswerten und dann für jeden Datensatz eine Struktur parsen, weil soweit ich sehe besteht eine Zeile aus einen Header einer Zahl und den Daten. Das kann man dann auch in csv oder xml oder json umkodieren oder auch ganz einfach in eine Tabelle schreiben, wenn die Struktur immer gleich ist. Wenn nicht so kann man aus dem Header und der Zahl einen Schlüssel bilden und den zusammen mit einer Datensatzkennung in der Tabelle abspeichern, die wird dann viele Datensätze beinhalten, aber jeder Datensatz ist eindeutig adressier und zuordenbar. Klingt komplizierter als es ist
Aber ich mache solche Sachen öfters.
Zum Zeilenweisen einlesen verwendet ich folgendes
Der TTextFileStream findest du in der angehängten Datei.
Das Beispiel soll nur zeigen, wie du Zeile für Zeile mittels TFS.Readln den Stream komfortabel bekommst. In dem Beispiel kannst du zum Beispiel eine ganze Datei in einen TStrings hineinladen und dann wo anders die Zeile Parsen.

Zum Zeilenweisen einlesen verwendet ich folgendes
Code: Alles auswählen
function ReadTextFirstLines(const FileName: string; MaxLines: integer;
TS: TStrings): boolean;
var
TFS : TTextFileStream;
i: integer;
begin
Result:= false;
if (not assigned(TS)) or (MaxLines < 1) or (FileName = '') then exit;
TFS := TTextFileStream.Create(FileName,fmOpenRead);
try
i := 0;
while (not TFS.Eof) and (i < MaxLines ) do
begin
TS.Append(TFS.ReadLn);
inc(i);
end;
Result:= true;
finally
TFS.Free;
end;
end;
Das Beispiel soll nur zeigen, wie du Zeile für Zeile mittels TFS.Readln den Stream komfortabel bekommst. In dem Beispiel kannst du zum Beispiel eine ganze Datei in einen TStrings hineinladen und dann wo anders die Zeile Parsen.
- Dateianhänge
-
- utextfilestream.pas
- (4.56 KiB) 36-mal heruntergeladen
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
Re: Import eines "wilden" Textfiles in SQLite
Oder so (Quick and Dirty, aber für überschaubare Datenmengen nicht unbedingt falsch für den einmaligen Import. Muss man bestimmt noch an die Gegebenheiten anpassen)
Sieht dann so aus:
Code: Alles auswählen
procedure TForm1.Button1Click(Sender: TObject);
var
SL, WL: TStringList;
SA: TStringArray;
i, j: integer;
Columns, Values: string;
begin
SL := TStringList.Create;
WL := TStringList.Create;
SL.LoadFromFile('/home/theo/adidata.txt'); //Hier sind die Daten drin
SA := Sl.Text.Split(['<eoh>'], TStringSplitOptions.ExcludeEmpty);
Memo1.Lines.Add(Trim(SA[0]));
Memo1.Lines.Add('-------- END HEADER --------');
SA := SA[1].Split(['<eor>'], TStringSplitOptions.ExcludeEmpty);
for i := 0 to Length(SA) - 1 do
begin
WL.Text := StringReplace(Trim(SA[i]), '<', '', [rfReplaceAll]);
WL.NameValueSeparator := '>';
Columns := '';
Values := '';
for j := 0 to WL.Count - 1 do
begin
Columns += WL.Names[j].Split(':')[0];
Values += QuotedStr(WL.ValueFromIndex[j]);
if j < WL.Count - 1 then
begin
Values += ',';
Columns += ',';
end;
end;
Memo1.Lines.Add('INSERT INTO table_name (' + Columns + ')');
Memo1.Lines.Add('VALUES (' + Values + ');');
end;
WL.Free;
SL.Free;
end;
QRZLogbook download for hb9fih
Date: Fri Jul 29 06:26:46 2022
Bookid: 19332
Records: 204
<ADIF_VER:5>3.1.1
<PROGRAMID:10>QRZLogbook
<PROGRAMVERSION:3>2.0
-------- END HEADER --------
INSERT INTO table_name (app_qrzlog_logid,app_qrzlog_qsldate,app_qrzlog_status,band,band_rx,call,comment,cont,country,cqz,distance,dxcc,email,eqsl_qsl_rcvd,eqsl_qsl_sent,freq,freq_rx,gridsquare,ituz,lat,lon,lotw_qsl_rcvd,lotw_qsl_sent,mode,my_city,my_country,my_cq_zone,my_gridsquare,my_itu_zone,my_lat,my_lon,my_name,name,qrzcom_qso_upload_date,qrzcom_qso_upload_status,qsl_rcvd,qsl_sent,qso_date,qso_date_off,qth,rst_rcvd,rst_sent,station_callsign,time_off,time_on,tx_pwr)
VALUES ('717291809','20220214','C','20m','20m','9K2YD','QTH EA8 -','AS','Kuwait','21','6363','348','sailor2251970@gmail.com','N','N','14.074','14.074','LL49AH17','39','N029 19.483','E048 00.615','N','N','FT8','EA8','Switzerland','14','IL07xs','28','N027 46.248','W018 02.520','Erich Rieder','Younes M H H ALMATROOK','20220115','Y','N','N','20220107','20220107','ALSHAAB','599','599','HB9FIH','1550','1550','15');
INSERT INTO table_name (app_qrzlog_logid,app_qrzlog_qsldate,app_qrzlog_status,band,band_rx,call,comment,cont,country,cqz,distance,dxcc,email,eqsl_qsl_rcvd,eqsl_qsl_sent,freq,freq_rx,gridsquare,ituz,lat,lon,lotw_qsl_rcvd,lotw_qsl_sent,mode,my_city,my_country,my_cq_zone,my_gridsquare,my_itu_zone,my_lat,my_lon,my_name,name,qrzcom_qso_upload_date,qrzcom_qso_upload_status,qsl_rcvd,qsl_sent,qso_date,qso_date_off,qth,rst_rcvd,rst_sent,station_callsign,time_off,time_on,tx_pwr)
VALUES ('722339967','20220214','C','40m','40m','SP8LM','QTH EA8 -','EU','Poland','15','1042','269','sp8lm@wp.pl','N','N','7.076','7.076','KN19FI','28','N049 22.233','E022 25.167','N','N','JT65','8820 Wädenswil','Switzerland','14','JN47if','28','N047 14.100','E008 40.933','Erich Rieder','Marek Jan Åagowski','20220129','Y','N','N','20220127','20220127','PolaÅczyk','599','599','HB9FIH','2105','2105','20');
-
- Beiträge: 11
- Registriert: Mi 20. Jul 2022, 10:45
- OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
- CPU-Target: 64Bit
- Wohnort: 8222 Beringen (CH)
- Kontaktdaten:
Re: Import eines "wilden" Textfiles in SQLite
Danke sehr - und erst noch ohne dbf ...
Ich mache mal beides ..
Ich mache mal beides ..
-
- Beiträge: 11
- Registriert: Mi 20. Jul 2022, 10:45
- OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
- CPU-Target: 64Bit
- Wohnort: 8222 Beringen (CH)
- Kontaktdaten:
Re: Import eines "wilden" Textfiles in SQLite
@Theo - ich danke Dir... selbstverständlich auch dem anderen Helfer.
habe dies nun etwas erweitert. Den Header braucht man nicht den kann man vorgängig in einem Text Editor eliminieren.
Interessant war dass mit dem einlesen des header immer nur 2 QSO0s aufbereitet wurden - aber das ist gelöst.
Habe mal Lots von 204 und 150 QSO's eingelesen, was sehr schnell geht und habe sie nun in der DB:
Mit flexiblen SELECTS, auch DISTINC kann ich nun auswerten was ich will.
Ich baue nun noch etwas "rundum Komfort" und Sicherheit ein.
Ganz am Ende des erstellten SQL gibt es noch einen leeren INSERT, das dann auf Fehler läuft, den muss ich noch eliminieren.
Hier noch, von Deiner Routine, meine etwas erweiterte Form:
habe dies nun etwas erweitert. Den Header braucht man nicht den kann man vorgängig in einem Text Editor eliminieren.
Interessant war dass mit dem einlesen des header immer nur 2 QSO0s aufbereitet wurden - aber das ist gelöst.
Habe mal Lots von 204 und 150 QSO's eingelesen, was sehr schnell geht und habe sie nun in der DB:
Mit flexiblen SELECTS, auch DISTINC kann ich nun auswerten was ich will.
Ich baue nun noch etwas "rundum Komfort" und Sicherheit ein.
Ganz am Ende des erstellten SQL gibt es noch einen leeren INSERT, das dann auf Fehler läuft, den muss ich noch eliminieren.
Hier noch, von Deiner Routine, meine etwas erweiterte Form:
Code: Alles auswählen
procedure TForm1.btnMEINClick(Sender: TObject);
var
SL, WL: TStringList;
SA: TStringArray;
i, j, ii : integer;
Columns, Values: string;
MyCursor: TCursor;
begin
MyCursor := Self.Cursor;
Self.Cursor := crHourGlass;
memo2.clear;
SL := TStringList.Create;
WL := TStringList.Create;
SL.LoadFromFile(workfile); //Hier sind die Daten drin
{
SA := Sl.Text.Split(['<eoh>'], TStringSplitOptions.ExcludeEmpty);
Memo2.Lines.Add(Trim(SA[0]));
Memo2.Lines.Add('-------- END HEADER --------');
SA := SA[1].Split(['<eor>'], TStringSplitOptions.ExcludeEmpty);
}
{Info
Habe daas von QRZ exportierte ADI File mutiert, dh ich habe den Header rausgelöscht
Den braucht man nicht
}
SA := SL.Text.Split(['<eor>'], TStringSplitOptions.ExcludeEmpty);
memo2.Append(SL.text);
ii := Length(SA);
showmessage('Anzahl QSO: ' + IntToStr(ii));
Self.Cursor := crHourGlass;
memo2.Clear;
//for ii := 0 to Length(SA) -1 do
begin
// SA := SA[0].Split(['<eor>'], TStringSplitOptions.ExcludeEmpty);
// Split wurde oben zl 255 schon gemacht
for i := 0 to Length(SA) - 1 do
begin
WL.Text := StringReplace(Trim(SA[i]), '<', '', [rfReplaceAll]);
WL.NameValueSeparator := '>';
Columns := '';
Values := '';
for j := 0 to WL.Count - 1 do
begin
Columns += WL.Names[j].Split(':')[0];
Values += QuotedStr(WL.ValueFromIndex[j]);
if j < WL.Count - 1 then
begin
Values += ',';
Columns += ',';
end;
end;
Memo2.Lines.Add('INSERT INTO table_name (' + Columns + ')');
Memo2.Lines.Add('VALUES (' + Values + ');');
end;
end;
WL.Free;
SL.Free;
Memo2.Lines.SaveToFile('xM2-dxcc.txt');
Self.Cursor := MyCursor;
end;