Einen Vector in mehreren Dateien abspeichern, ab einer bestimmten Dateigröße.



  • @wob sagte in Einen Vector in mehreren Dateien abspeichern, ab einer bestimmten Dateigröße.:

    einfach eine Map

    Das möchte ich unterstreichen.
    Du hast doch mehr oder weniger einfach nur vor, ein Key-Value-Format in ein csv-Format umzuwandeln.
    Das ist mit einer map doch gut zu erledigen.

    Ohne jetzt vom Thema ablenken zu wollen, aber was halt sofort aufgefallen ist:
    Deine Basisklasse hat keinen virtuellen Destructor und auch die print-Funktion ist nicht virtuell, was wohl kaum beabsichtigt war.



  • aber eine map kann nur key - value Paare halten oder?
    Der Anfang eines Blockes ist jedoch immer "$TimeStamp: Datum Uhrzeit". Hier möchte ich Datum und Uhrzeit trennen und könnte dann den Datensatz nicht mehr als key - value speichern, da ich ja ein key - value - value Paar erhalten würde ...

    @Jockelx danke für den Hinweis 🙂



  • @prog64 sagte in Einen Vector in mehreren Dateien abspeichern, ab einer bestimmten Dateigröße.:

    aber eine map kann nur key - value Paare halten oder?
    Der Anfang eines Blockes ist jedoch immer "$TimeStamp: Datum Uhrzeit". Hier möchte ich Datum und Uhrzeit trennen und könnte dann den Datensatz nicht mehr als key - value speichern, da ich ja ein key - value - value Paar erhalten würde ...

    @Jockelx danke für den Hinweis 🙂

    Du kannst doch als Value auch ein std::pair<Date, Time> nehmen.

    vereinfacht dargestellt:

    std::unordered_map<std:.string, std::pair<Date, Time>> Data;
    Data[ MyKey ] = std::make_pair( MyDate, MyTime );
    


  • @It0101 sagte in Einen Vector in mehreren Dateien abspeichern, ab einer bestimmten Dateigröße.:

    Du kannst doch als Value auch ein std::pair<Date, Time> nehmen.

    Ich weiß nicht was du im Kopf hast; mein vorgehen wäre sowas:

    void readFile(std::vector<std::map<string, string>>& values)
    {
    // füllt zu jedem Datasatz die map mit 
    // ReqTimeMs->value
    // StatusCode->value,...
    ...
    }
    
    void writeFile(const std::vector<std::map<string, string>>& values)
    {
      std::array<std::string> header = {"ReqTimeMs", "StatusCode",...};
      for(const auto& h : headers)
      {
         for(auto& row : values)
         {
            datei << row[h] << ';';
         }
         datei << '\n';
      }
    
    

    Für spezial-Fälle wie Zeit oder letzter Eintrag dann halt gesondert beachten:

       if( h == "Zeit")
         datei << getTime(row["$TimeStamp"]) << ';';
       else if( h == "Datum")
         datei << getDate(row["$TimeStamp"]) << ';';
       else ...
    
    
    

    Edit: Die Header und Map-Keys müssen natürlich passen; sonst müssen die auch gemappt werden.



  • Vielen Dank für eure Vorschläge 🙂
    Ich habe es jetzt mal mit einer unorderd_map probiert, jedoch hab ich hier ein ähnliches Problem, was die Speicherauslastung angeht. Lese hier ca 35 MB Textfile ein und erhalte ca 750 MB im Prozesspeicher von Visual Studio (Debbuging Mode). Beim abspeichern der Daten in eine csv steigt dies sogar auf zwischenzeitlich mehrere GB, während die Ausgabe datei letztlich nur wenige 30 MB groß ist. Ich hab die Spezial-Fälle jetzt mal weggelassen ...

    Auch verstehe ich nicht ganz wie ich es beim abspeichern hinbekommen soll das die csv wie folgt aussieht:

    Datum:;Zeit:; ....
    eingelesener Wert1; Eingelesener Wert2; ...
    ...
    usw.

    #include<iostream>
    #include<string>
    #include<vector>
    #include<array>
    #include<unordered_map>
    #include<fstream>
    
    
    using namespace std;
    
    void checkline(string& line1, string& line2, vector<unordered_map<string, string>>& data)
    {
    	unordered_map<string, string> temp;
    	if (line1 == "\$TimeStamp:")
    	{
    		temp.insert({ "Datum:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "AuthUser:") {
    		temp.insert({ "Account:",line2 });
    		temp.insert({ "TAG:","Web" });
    		data.push_back(temp);
    	}
    	if (line1 == "Partner:")
    	{
    		temp.insert({ "IP:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "Referer:")
    	{
    		temp.insert({ "Referer:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "UserAgent:")
    	{
    		temp.insert({ "UserAgent:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "RequestLine:")
    	{
    		temp.insert({ "RequestLine:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "UserName:") {
    		temp.insert({ "Account:",line2 });
    		temp.insert({ "TAG:","Andere" });
    		data.push_back(temp);
    	}
    	if (line1 == "RemoteIP:")
    	{
    		temp.insert({ "IP:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "BytesFromServer:")
    	{
    		temp.insert({ "Bytes vom Server:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "BytesToServer:")
    	{
    		temp.insert({ "Bytes zum Server:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "MessageSent:")
    	{
    		temp.insert({ "Messages Sent:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "MessageDeleted:")
    	{
    		temp.insert({ "Messages Deleted:",line2 });
    		data.push_back(temp);
    	}
    	if (line1 == "TotalOpenTime:")
    	{
    		temp.insert({ "Aktivitätsdauer:",line2 });
    		data.push_back(temp);
    	}
    }
    
    
    void readFile(const string& dateiname, vector<unordered_map<string, string>>& values)
    {
    	try
    	{
    		ifstream datei(dateiname);
    		while (datei.good())
    		{
    			string line;
    			getline(datei, line);
    
    			int pos = line.find_first_of(' ');
    			if (pos > 0)
    			{
    				string line1 = line.substr(0, pos);
    				string line2 = line.substr(pos);
    				line2 = ltrim(line2);
    				checkline(line1, line2, values);
    			}
    		}
    	}
    	catch (const std::exception& e)
    	{
    		cout << e.what() << endl;
    	}
    }
    
    void writeFile(const string& dateiname,vector<unordered_map<string, string>>& data)
    {
    	try
    	{
    		ofstream datei(dateiname);
    		if (datei.good())
    		{
    			array<string,13> header = { "Datum:", "Zeit:", "Account:", "IP:","TAG:","RequestLine:","Referer:","UserAgent:","Aktivitätsdauer:","Bytes vom Server:","Bytes zum Server:","Messages Deleted:","Messages Sent:" };
    			for (const auto& h : header)
    			{
    				for (auto& rows : data)
    				{
    					datei << rows[h] << ";" ;
    				}
    				datei << endl;
    			}
    		}
    		else
    		{
    			throw "IO-Error";
    		}
    	}
    	catch (const string& e)
    	{
    		cout << e << endl;
    	}
    
    
    }
    
    int main(int argc, char** argv)
    {
    	locale loc("german");
    	locale::global(loc);
    	string dateiname;
    
    	vector<unordered_map<string, string>> Data;
    	
    	cout << "Dateipfad: ";
    	getline(cin, dateiname);
    
    	readFile(dateiname, Data);
    
    	cout << "Dateiname: ";
    	getline(cin, dateiname);
    	writeFile(dateiname, Data);
    
    	return 0;
    }
    


  • Wieso denn so viele push_back?

    Ein push_back, sobald der gesamte Datensatz eingelesen ist, nicht ein push_back pro Zeile.

    Und da du eh nichts mit den Datensätzen machst, kannst du sie auch gleich direkt rausschreiben anstatt sie in einem vector zu sammeln.



  • @wob Ich lese nicht alles ein sondern nur die Werte die in den if-Abfragen stehen, sprich ich sortiere unnötige Daten im Vorfeld aus.



  • Überlege dir die Logik in deiner bisherigen checkline-Funktion noch mal:
    du erzeugst zurzeit eine unordered_map und fügst dann genau einen Wert (Edit: Datensatz) hinzu und damit füllst du sofort den vector.

    Fülle den vector (bzw. wie schon geschrieben: schreibe gleich die Daten raus) sobald du das Ende des Datensatzes gelesen hast (dazu solltest du dann die unordered_map, statt des vector als Funktionsparameter übergeben).

    PS: Du kannst else if in der Funktion verwenden und deine string&-Parameter sollten const sein...



  • @Th69 sagte in Einen Vector in mehreren Dateien abspeichern, ab einer bestimmten Dateigröße.:

    du erzeugst eine unordered_map und fügst dann genau einen Datensatz hinzu und damit füllst du den vector.

    Eben nicht. Sobald auch nur eine der interessanten Zeilen auftaucht, findet das push_back statt. Eben nicht erst, wenn der Datensatz zu Ende ist. Ein Datensatz scheint zu Ende zu sein, wenn die $UpdatedBy:-Zeile auftaucht (so war es im ersten Code). Man sollte das push_back also nur dort machen. Und zwischenzeitlich darf man natürlich nicht die Map für jede Zeile neu erstellen, sondern muss sie solange behalten.

    Bzgl:

    ich sortiere unnötige Daten im Vorfeld aus.

    kannst du machen. Aber du könntest auch erstmal ganz dumm einfach jede splitbare Zeile in die Map schreiben und bei der csv-Ausgabe einfach nur die ge

    Fülle den vector (bzw. wie schon geschrieben: schreibe gleich die Daten raus) sobald du das Ende des Datensatzes gelesen hast

    Genau!



  • @wob: Ich habe dort nur beschrieben, was der Code von @prog64 zurzeit macht und dann im nächsten Satz, wie er ihn ändern soll...

    Edit: Oder meinst du das Wort "Datensatz"? Kannst auch "Wert" dafür nehmen...
    Habe meinen Beitrag oben editiert.



  • @Th69 Ja, ich meinte das Wort "Datensatz". Das sind für mich mehrere Key-Value-Paare, nämlich all die, die nachher in der csv-Datei in einer Zeile landen sollen. Dein Edit macht das jetzt auch gleich viel klarer 👍


Anmelden zum Antworten