C++ Gezielt Daten aus txt einlesen

NichTec

Ensign
Registriert
Juli 2014
Beiträge
167
Hallo zusammen,

ich bin gerade an einem kleinen C++ Projekt. Dabei habe ich eine kleine txt als Datenbank angelegt. Es sollen nicht viele Daten werden daher wollte ich nicht auf Mysql, etc zurückgreifen.

Ich habe in der txt die Daten (Beispiel) so vorliegen:

1;Titel;Autor;0123456789
2;Titel2;Autor2;9876543210

Jetzt soll der Anwender die ID (in unserem Fall 1 oder 2) eingeben und das Programm dann alle weiteren Felder in einzelne Variablen speichern sodass sie auch einzeln geändert und gelesen werden können.

Danke für Eure Tipps.
 
Ich würde da jetzt mit nem Array arbeiten.
txt Datei in ein Array packen, nach den Änderungen das Array wieder in der txt Datei speichern.
 
Wenn die Datenbank eh so klein ist; wieso nicht ein relativ simples shell script? Solltest du unter Linux arbeiten; sowas in der Preisklasse:
Code:
# z.B.
file="$1"

echo -n "ID: "
read id
echo -n "Current record: "
egrep "^$id;" "$file"

echo -n "New Title: "
read title
echo -n "New Autor: "
read autor
echo -n "New number: "
read number

content=$(cat "$file")
sed "s/^$id;.*$/$id;$title;$autor;$number/" <<< "$content" > "$file"
 
Ich würde da jetzt mit nem Array arbeiten.
txt Datei in ein Array packen, nach den Änderungen das Array wieder in der txt Datei speichern.
Bitte nicht! Ein Array hat in C++ überhaupt nichts zu suchen (außer C++11 std::array und das wäre hier auch Unsinn)
Da du vorher nicht weißt, wie viele Datensätze es gibt schreit die Anwendung nach einer "dynamischen" Datenstruktur - also eine wo die Größe noch NICHT vorher festgelegt sein muss.
Also unbedingt einen vector verwenden und die Daten mittels push_back Zeile für Zeile einfügen.

Du brauchst also ein C++ Programm mit einem struct/einer Klasse "Datensatz" oder so mit den Membern Titel, Autor, Nummer und liest zeilenweise die Datei ein: Input/output with files.
Danach, wie Egon schon vorschlägt, einfach alles wieder in die Datei zurückschreiben. Das wäre der einfachste Ansatz. Bei großen Datenmengen ist es natürlich Unsinn immer die komplette Datei zu schreiben aber mit diesen einfachen Methoden scheint das der normale Weg zu sein. "Ersetzen" einer mittleren Zeile ist nicht so einfach: Beispiel1, Beispiel2

Edit: Wenn du wirklich über die ID gehen willst (und diese nicht notwendigerweise steigend nummeriert ist bzw die Reihenfolge evtl mal tauscht) dann solltest du statt meinem vorgeschlagenen Vector mit einer std::map arbeiten.
Dh du holst zB den Datensatz 3 mittels
Code:
int id = 3;
Datensatz tempDatensatz;
m_db.getDatensatz(id, &tempDatensatz);

// Und die Klasse DB hat dann als Member
void DB::getDatensatz(int id, Datensatz* daten)
{
  std::map<int, Datensatz>::iterator it = m_data.find(id);
  if (it != m_data.end()) // id wurde gefunden
    daten = it;
  else // id wurde nicht gefunden
    daten = NULL;
}
Trotzdem würde ich an deiner Stelle ERSTMAL mit einem vector arbeiten und diese Änderung erst später durchführen wenn du dich etwas sicherer fühlst.
 
Zuletzt bearbeitet:
Bin selber gerade am C++ lernen, aber hier ein Ansatz der helfen sollte. Kommt natürlich auch drauf an als welchen Typ du den vierten Parameter speichern willst, ich habe hier mal string genommen. Es wird wohl gleich asdfman auftauchen und über scanf und char [500] schimpfen aber als kleiner Ansatz sollte das reichen. Probiers aus sag mir ob es funktioniert.


Code:
int ReadFile(char *filename)
{
	fstream myFile;
	myFile.open(filename);

	if (myFile.is_open())
	{
		char line[500];

		//Parse object file line by line
		while (myFile.good())
		{
			myFile.getline(line,500);
                        int i;
                        string s1;
                        string s2;
			string s3;

			sscanf(line,"%d;%s;%s;%s", &i, &s1, &s2,&s3);
			
		}

		myFile.close();

	}
	else
	{
		cout << "Konnte Datei '" << filename << "' nicht lesen. \n";
		return false;
	}

	return true;
}

BTW hier werden die Werte nur gelesen speichern musst du die schon selbst. Würde aber vielleicht einen struct mit 4x std::vector deklarieren und den Spaß dort speichern.

It's dangerous to go alone, Take this:

Code:
_CRT_SECURE_NO_WARNINGS

Hm scheint nicht ganz zu funktionieren. Vielleicht kann jemand helfen den Code zu berichtigen.
 
Zuletzt bearbeitet:
NichTec schrieb:
Danke für Eure Tipps.

Du könntest die Datei mit einem std::ifstream einlesen. Entweder immer jede Zeile einzeln oder gleich die ganze Datei auf einen Schlag. Bei letzterem Ansatz müßtest du eben selbst immer zum nächsten newline-Character vorhüpfen und die Datei in ihre Zeilen zerlegen.

Dann trennst du jede Zeile an Hand des von dir benutzten Trennzeichens (also dem Semikolon) in ihre einzelnen Einträge auf. Im Grunde würdest du einen CSV-Parser bauen.
 
IKäsebrot schrieb:
Es wird wohl gleich asdfman auftauchen und über scanf und char [500] schimpfen

Weil, wenn ich das sage, es ja nur dummes Gegacker ohne Berechtigung ist!

Außerdem will ich mich beschweren, dass du heimlich dieses Foto von mir gemacht hast :(
talk-too-much-blah-blah-blah-o.gif
 
Zuletzt bearbeitet:
asdfman schrieb:
Weil, wenn ich das sage, es ja nur dummes Gegacker ohne Berechtigung ist!

Außerdem will ich mich beschweren, dass du heimlich dieses Foto von mir gemacht hast :(

Ne war nicht böse gemeint. Ich hab selber keinen Plan und steige gerade in C++ ein. Bin dir echt für jeden Tipp dankbar. habe mir auch nach deinen Beiträgen durchgelesen warum scanf nicht gut ist, danke.

Kannst du vielleicht den Code oben so modifizieren, dass er läuft? Ich kriegs net weiter hin.
 
Zuletzt bearbeitet:
Ich würde die Zeile zeichenweise durchgehen und die nötigen Puffer bei Bedarf vergrößern. Ich kann aber kein C++, deshalb poste ich hier keinen Code und außerdem gehe ich davon aus, dass das auch in C++ keine Zweizeilenmodifikation für mal eben so ist.

Edit: Den Compiler anzuweisen, bei Warnungen über Sicherheitsrisiken doch bitte einfach die Fresse zu halten, ist keine gute Idee, wenn man nicht weiß, was man tut.
 
Zuletzt bearbeitet:
Code:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>

std::vector<std::string> split_string(const std::string& str,
                                      const std::string& delimiter)
{
    std::vector<std::string> strings;

    std::string::size_type pos = 0;
    std::string::size_type prev = 0;
    while ((pos = str.find(delimiter, prev)) != std::string::npos)
    {
        strings.push_back(str.substr(prev, pos - prev));
        prev = pos + 1;
    }

    // To get the last substring (or only, if delimiter is not found)
    strings.push_back(str.substr(prev));

    return strings;
}

std::vector< std::string > parse_CSV_line( const std::string& line, char delimiter )
{
	bool inQuotes = false;
	std::string currentValue;
	std::vector< std::string > record;

	for ( std::string::size_type i = 0; i < line.length(); ++i )
	{
		const char currentChar = line[ i ];

		if ( ! inQuotes && currentValue.empty() && currentChar == '"' )
		{
			inQuotes = true;
		}
		else if ( inQuotes && currentChar == '"' )
		{
			if ( i + 1 < line.length() && line[ i + 1 ] == '"' )
			{
				currentValue.push_back( currentChar );
				++i;
			}
			else
			{
				inQuotes = false;
			}
		}
		else if ( ! inQuotes )
		{
			if ( currentChar == delimiter )
			{
				record.push_back( currentValue );
				currentValue.clear();
			}
			else if ( currentChar == '\r' || currentChar == '\n' )
			{
				record.push_back( currentValue );
				return record;
			}
			else
			{
				currentValue.push_back( currentChar );
			}
		}
		else
		{
			currentValue.push_back( currentChar );
		}
	}

	record.push_back( currentValue );

	return record;
}

std::string readFileIntoString( const std::string& fileName )
{
	std::ifstream ifs( fileName, std::ios::in );

	if ( ! ifs )
	{
		std::cerr << "Failed to open file for reading!\n";
		return std::string();
	}

	return std::string( ( std::istreambuf_iterator< char >( ifs ) ), std::istreambuf_iterator< char >() );
}

int main()
{
	const std::string fileContent = readFileIntoString( "D:\\tmp\meineDatei.txt" );

	if ( fileContent.empty() )
	{
		// war wohl nix
		return 1;
	}

	const std::vector< std::string > lines = split_string( fileContent, "\n" );

	for ( auto it = lines.begin(); it != lines.end(); ++it )
	{
		const std::vector< std::string > fieldsInThisLine = parse_CSV_line( *it, ';' );

		const std::string id_string = fieldsInThisLine.at( 0 );
		const std::string title_string = fieldsInThisLine.at( 1 );
		const std::string author_string = fieldsInThisLine.at( 2 );

		// ...
	}

	return 0;
}

Code nicht getestet ...nicht mal kompiliert; es kann also sein, daß da der eine oder andere Kompilierfehler drin ist. Die Funktion split_string() habe ich von hier geklaut, die Funktion parse_CSV_line() habe ich aus einem meiner Projekte kopiert und schnell etwas modifiziert und readFileIntoString() mal eben selbst zusammengeschustert.
 
Zuletzt bearbeitet: (Hatte Definition des vectors 'record' vergessen.)
Hallo zusammen,
erst einmal vielen Dank über sämtliche Vorschläge. Ich werde jetzt natürlich nicht auf jeden Post einzeln eingehen können daher bitte nicht böse sein, wenn ich irgendwas nicht weiter verfolge. Ich versuche später drauf zurück zu kommen.

Von unten:

@antred: Soweit scheint mein Compiler das zu verstehen, nur mit dem Bezeichner "record" weiß er nicht was zu machen? Fehlt irgendein include?

@asdfman: Könntest du mal bitte den Link poste, warum scanf schlecht ist? Würde mich interessieren. Ich bin selber nur Anfänger und bin um jeden Tipp dankbar.

@ IKäsebrot: Der Code sieht, trotz scanf, logisch aus, zumindest für mich als Anfänger verstehe sofort, was der Code machen soll.

Könnte mir jemand Kurz erklären was Vektoren und Arrays sind? In Google finde ich nur Artikel in Fachsprache bei denen ich genauso schlau bin wie vorher :(
 
NichTec schrieb:
@antred: Soweit scheint mein Compiler das zu verstehen, nur mit dem Bezeichner "record" weiß er nicht was zu machen? Fehlt irgendein include?

Nee, aber ich Depp hatte vergessen, den vector 'record' zu definieren. Fehler beim copy&paste. Ich hab's korrigiert.

Könnte mir jemand Kurz erklären was Vektoren und Arrays sind? In Google finde ich nur Artikel in Fachsprache bei denen ich genauso schlau bin wie vorher :(

Versuch's mal bei Wikipedia.

Arrays (Felder) -> http://de.wikipedia.org/wiki/Feld_(Datentyp)

Und wenn du das gelesen & verstanden hast, dann ist ein vector auch nix kompliziertes mehr, denn ein vector ist im Wesentlichen eigentlich nur eine Art Array, dessen Größe man zur Laufzeit dynamisch vergrößern kann.
 
NichTec schrieb:
@asdfman: Könntest du mal bitte den Link poste, warum scanf schlecht ist? Würde mich interessieren. Ich bin selber nur Anfänger und bin um jeden Tipp dankbar.
Warum muss ich dafür einen Link posten? scanf() hat keine Ahnung, wieviel Platz in den Speicherbereichen ist, in das es schreiben soll.
Wenn du unbedingt einen Link brauchst, um zu verstehen, warum das schlecht ist: http://de.wikipedia.org/wiki/Pufferüberlauf
 
Zurück
Oben