CSV Datei unbekannter Größe einlesen (wxWidgets)
-
Hallo zusammen,
zunächst weiß ich nicht genau ob es das Richtige Forum ist, also falls nicht bitte nicht schimpfen:-)
Etwas zu mir, ich habe recht gute Kentnisse in C (aus dem Mikroprozessorbereich) jedoch kaum Kenntnisse in c++. Ich möchte mit wxWidgets daten eines Geräte grafisch darstellen. Die Daten kommen aus einer CSV Datei und sehen wie folgt aus:
Date;Time;Station ID;Charger Mode;Ubat;Iin;Iout;Ibat;Uin;Batt. Temp.;Uabsoprtion;Ufloat;Ucutoff;Ucutoff_recovery;Ilim_bat;AH_counter;MEMfree;PWM;MPP_PWM;IP;AGPS_IP;Iout_offset;Iin_offste;ADCoffset;GPSlatitude;GPSlongitude;GPSaltitude;Batt_cells;Batt_Nr;Batt_Capacity;U_absortion_cell;t_absorption;Uabsorption_exit_cell;u_float_cell;t_float_exit;u_float_exit;u_cuttoff_cell;u_cutoff_recovery_cell;temp_coefficient;i_lim_c_x;u_equalize_cell;t_equalie_time;t_equalize_int;p_in_act;p_out_act;p_in_y;p_out_y;p_in_t;p_out_t;output_state;input1;input2;input3;input4;Last Log Message 12/9/2011;10:1:1;3146323432340c02000900;2;25.98;00.00;00.38;-0.02;00.00;21.00;28.94;27.50;24.00;25.20;04.00;00.00;1739;0255;0255;010.170.141.015;000.000.000.000;170;167;168;000.000000;000.000000;000.000000;12;00;012;02.40;00180;2.28;2.28;00030;2.23;2.00;2.10;-0.004;00003;0.00;005;005;000000;000000;000000;000000;000000;000000;1;4095;4095;4095;4095 12/9/2011;10:1:47;3146323432340c02000900;2;25.95;00.00;00.00;-0.02;00.00;21.00;28.94;27.50;24.00;25.20;04.00;00.00;1739;0255;0255;010.170.141.015;000.000.000.000;170;167;168;000.000000;000.000000;000.000000;12;00;012;02.40;00180;2.28;2.28;00030;2.23;2.00;2.10;-0.004;00003;0.00;005;005;000000;000000;000000;000000;000000;000000;1;4095;4095;4095;4095 12/9/2011;22:59:31;3146323432340c02000900;2;25.93;00.00;00.00;-0.02;00.00;22.00;28.90;27.46;24.00;25.20;04.00;00.01;1739;0255;0255;010.181.134.218;000.000.000.000;172;167;163;000.000000;000.000000;000.000000;12;00;012;02.40;00180;2.28;2.28;00030;2.23;2.00;2.10;-0.004;00003;0.00;005;005;000000;000000;000000;000000;000000;000000;1;4095;4095;4095;4095 12/9/2011;23:0:1;3146323432340c02000900;2;25.95;00.00;00.00;-0.02;00.00;22.00;28.90;27.46;24.00;25.20;04.00;00.01;1739;0255;0255;010.181.134.218;000.000.000.000;172;167;163;000.000000;000.000000;000.000000;12;00;012;02.40;00180;2.28;2.28;00030;2.23;2.00;2.10;-0.004;00003;0.00;005;005;000000;000000;000000;000000;000000;000000;1;4095;4095;4095;4095
Also durch Semikolon getrennt. Die Größe der Datei kann unterschiedlich sein.
Ich hab jetzt mal wie folgt angefangen:// Gespeicherte Datensätze laden // -------------------------------- // CSV Datei öffnen wxTextFile file(log_file_path ); if (file.Exists()==false) { wxMessageBox("Kann LOG Datei nicht öffnen"); return; } struct Daten { wxDateTime date_time; wxString station_id[30]; long mode; double u_batt; double i_in; }; wxString Kopfzeile; Kopfzeile = file.GetFirstLine(); wxString line; while(file.Eof()==false) { // Hier muss die Datei Zeilenweise gelesen werden und den Variablen // zugeordnet werden line = file.GetNextLine(); }
Wie mache ich es die Auftrennung der Zeile jetzt am besten?
Und noch viel wichtiger, wie bekomme ich die Struktur in ein Array mit variabler Größe?
Später soll aus einer anderen Klasse der Zugriff auf diese Datensätze möglich sein, irgenwie sowas in der art:
BatterieSpannung =Station.GetDatensatz(Datensatznummer).u_batt;
Wie macht man sowas? Hab was von vectoren gelesen aber komme nicht richtig klar damit...
Gruß
Falko
-
Koennte man in etwa so machen:
int alt; int neu; bool success; wxVector<Daten> DatenVec; while (file.Eof() == false) { success = false; Daten Data; line = file.GetNextLine() neu = line.find(";"); if (neu == wxString::npos) break; wxDateTime date; wxString::const_iterator end; if (!date.ParseDate(line.substr(alt+1, neu-alt+1), &end)) // +1 wegen Semikolon break; Data.date_time = date; bool succ2; for (size_t i=0; i<30; i++) { succ2 = false; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; Data.station_id[i] = line.substr(alt+1, neu-alt); succ2 = true; } if (!succ2) break; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; if (!line.substr(alt+1, neu-alt+1).ToLong(&Data.mode)) break; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; if (!line.substr(alt+1, neu-alt+1).ToDouble(&Data.u_batt)) break; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; if (!line.substr(alt+1, neu-alt+1).ToDouble(&Data.i_in)) break; success = true; DatenVec.push_back(Data); } if (!success) { wxMessageBox("Fehlerhafte Datei"); }
Ich habs nicht getestet und nur schnell "dahingeschmiert"
wxVector laesst sich wie std::vector verwenden.Die einzelnen Elemente koenntest du so durchgehen:
for (size_t i=0; i<DatenVec.size(); i++) { // mach was mit DatenVec[i] (Daten) }
-
Vielen Dank erstmal
Ich versuche gerade den code zu verstehen und umzusetzen. Leider hänge ich schon bei
wxVector<Daten> DatenVec;
Compiler sagt mir an dieser Stelle:
error: 'wxVector' was not declared in this scope|Obwohl ich die include Datei:
#include <wx/vector.h>
eingebunden habe. Eine Idee woran das liegen kann?
Ich habe dann auch versucht statt wxVector den STL vector zu verwenden:
#include <vector>
und
vector<Daten> DatenVec;
Dann bekomme ich allerdings den Fehler:
error: template argument for 'template<class _Alloc> class std::allocator' uses local type 'Station::Station(wxString, wxString, interface_types_t, int)::Daten'
E:\projekte\greenController\trunk\tools\kommTool\station.cpp|126|error: trying to instantiate 'template<class _Alloc> class std::allocator'|
E:\projekte\greenController\trunk\tools\kommTool\station.cpp|126|error: template argument 2 is invalid|
Wenn ich statt der Struktur "Daten" ein int benutze funktioniert es, aber das bringt mir nicht viel.... Funktioniert das mit dem Vektoren für Strukturen nicht???
Gruß
FalkoGruß
-
spacevoyager schrieb:
wxVector<Daten> DatenVec;
Compiler sagt mir an dieser Stelle:
error: 'wxVector' was not declared in this scope|Obwohl ich die include Datei:
#include <wx/vector.h>
eingebunden habe. Eine Idee woran das liegen kann?
Seltsam. Sicher das du die Header-Datei eingebunden hast bevor du wxVector verwendet hast?
Ansonsten, wirf mal einen Blick in die Header-Datei. Da muesste wxVector definiert sein...spacevoyager schrieb:
Ich habe dann auch versucht statt wxVector den STL vector zu verwenden:
#include <vector>
und
vector<Daten> DatenVec;
Dann bekomme ich allerdings den Fehler:
error: template argument for 'template<class _Alloc> class std::allocator' uses local type 'Station::Station(wxString, wxString, interface_types_t, int)::Daten'
E:\projekte\greenController\trunk\tools\kommTool\station.cpp|126|error: trying to instantiate 'template<class _Alloc> class std::allocator'|
E:\projekte\greenController\trunk\tools\kommTool\station.cpp|126|error: template argument 2 is invalid|
Wenn ich statt der Struktur "Daten" ein int benutze funktioniert es, aber das bringt mir nicht viel.... Funktioniert das mit dem Vektoren für Strukturen nicht???
Doch. Aber du musst die Struktur im globalen Scope definieren. MinGW mag wohl keine lokal definierten Strukturen...
Einpaar Erklaerungen zum Code:
-
wxDateTime::ParseDate
liest ein Datum ein und teilt es den auf. Der const_iterator zeigt dann an die Stelle wo das Parsen aufgehoert hat (eigentlich koennte man hier noch pruefen ob der iterator auf end() zeigt...) -
wxString::find
sucht nach einem String. Optional kann man im zweiten Parameter angeben, wo die Suche gestartet werden soll. Wenn nichts gefunden wurde wirdwxString::npos
zurueckgegeben. -
wxString::substr
teil ein String auf. Der erste Parameter ist die Startposition und der zweite die Laenge (optional). -
wxString::ToLong
konvertiert einen String in einen long. Als Parameter wird ein Zeiger zur long-Variable benoetigt. Gibt true zurueck, wenn die Konvertierung erfolgreich war.
- Im obigen Beispiel habe ich die Funktion
wxString::ToDouble
verwendet, die aehnlich funktioniert wie ToLong aber fuer einen double. Das ist aber falsch, weil ToDouble eine lokale Repraesentation der Zahl erwartet (Komma statt Punkt). Stattdessen koennen wir aberwxString::ToCDouble
verwenden, die einen Punkt als Komma akzeptiert.Der Rest des Codes duerfte ziemlich selbsterklaerend sein.
Ich hab noch einige Fehler in meinem Code entdeckt und hab sie ausgebessert.
Das hier klappt (getestet):int alt; int neu; bool success; wxVector<Daten> DatenVec; while (file.Eof() == false) { success = false; Daten Data; line = file.GetNextLine() neu = line.find(";"); if (neu == wxString::npos) break; wxDateTime date; wxString::const_iterator end; if (!date.ParseDate(line.substr(0, neu), &end)) break; Data.date_time = date; bool succ2; for (size_t i=0; i<30; i++) { succ2 = false; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; Data.station_id[i] = line.substr(alt+1, neu-alt-1); succ2 = true; } if (!succ2) break; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; if (!line.substr(alt+1, neu-alt-1).ToLong(&Data.mode)) break; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; wxString test = line.substr(alt+1, neu-alt-1); if (!line.substr(alt+1, neu-alt-1).ToCDouble(&Data.u_batt)) break; alt = neu; neu = line.find(";", alt+1); if (neu == wxString::npos) break; if (!line.substr(alt+1, neu-alt-1).ToCDouble(&Data.i_in)) break; success = true; DatenVec.push_back(Data); } if (!success) { wxMessageBox("Fehlerhafte Datei"); }
-
-
bin jetzt erst dazu gekommen weiter zu machen... es hat soweit alle geklappt, ein paar Sachen mußte ich noch umschreiben z.B. das mit dem wxVector hat nicht funktioniert, mit Vektor hats geklappt..ToCDouble gab es beiu mir nicht... vielleicht hab ich ne ältere Version von wxWidgets..aber auf jedefall klapps jetzt alles
Vielen Dank!
-
wxStringTokenizer zum Splitten einer Zeile
bei Qt gehts noch einfacher
QString zeile = "abc;defg;hijkl;mno";
QStringList list = zeile.split( ";" );