C++ Daten von Datei in vector speichern & ausgeben

Zephyro

Ensign
Registriert
Juni 2011
Beiträge
138
Guten Abend CB'ler,

ich versuche heute schon den ganzen abend den Inhalt einer Datei (.txt) in einen vector zu speichern und diesen danach gleich auszugeben.
Bisher leider ohne Erfolg. Es gibt zwar Beispiele im Netz, aber keines hilft mir richtig weiter.

Ich möchte zeichenweiße die Daten der Datei in den vector schreiben und danach diesen wieder zeichenweise ausgeben.

Hier mein C++ Code:

Code:
std::fstream file_stream;

std::vector<char> data;
std::vector<char>::iterator count;
count = data.begin();

file_stream.open("Test.txt", std::ios::in | std::ios::app)

while (!file_stream.eof())
{
	file_stream.read(&data[0], data.size());
	std::cout << data.at(*count) << std::endl;
	count++;
}

Wenn ich den Code ausführe, dann erhalte ich "Debug Assertion Failed!"
Expression: vector subscript out of range.

Weiß jemand Rat?

Danke schonmal im Vorraus!

MfG Zephyro
 
Bevor ich anfange, Korrekturen vorzuschlagen ... darf man fragen, warum es ausgerechnet ein vector sein soll? Warum nicht ein std::string-Objekt? Wenn es sich bei dem Dateiinhalt wirklich um Text handelt, wäre das doch weitaus sinnvoller, oder?
 
antred schrieb:
Bevor ich anfange, Korrekturen vorzuschlagen ... darf man fragen, warum es ausgerechnet ein vector sein soll? Warum nicht ein std::string-Objekt? Wenn es sich bei dem Dateiinhalt wirklich um Text handelt, wäre das doch weitaus sinnvoller, oder?

Ich habs vor ner stunde mal mit std::string versucht, aber da hatte ich dann schwierigkeiten beim casten von const char* nach char*. Mit const_char<char*>(meinString.c_str()) hab ich versucht, das zu casten, aber konnte es trotzdem nicht an eine char*-Variable übergeben.

Das vector-element ist mir lieber weil ich nacher den textinhalt zeichenweise auseinanderpflücken muss und mit vector.at() kann ich dann da geschickter damit arbeiten (glaube ich zumindest ;) ).

mfg
 
vector<char>? vector<string> hätte ich ja noch für eine zeilenweise Speicherung verstanden...

vector.at( i ) kannst du genauso mit strings über string machen. Btw: const_cast().
 
std::string bietet dir ebenfalls eine at()-Methode. Also, schau mal her. ;)

Code:
#include <fstream>
#include <iostream>
#include <string>
 
int main()
{
	// Wir können die Datei gleich direkt im Konstruktor des ifstream-Objektes öffnen.
	std::ifstream in( "Test.txt", std::ios_base::in );
	
	// Wenn's nicht geklappt hat ...
	if ( ! in )
	{
		std::cerr << "Konnte Datei nicht oeffnen!\n";
		return 1;
	}
	
	// std::string bietet einen Konstruktor, über den man den String über zwei Input-Iteratoren befüllen kann.
	std::string data( ( std::istreambuf_iterator< char >( in ) ), std::istreambuf_iterator< char >() );
	 
	// Inhalt der eben ausgelesenen Datei auf Bildschirm ausgeben
	for ( std::size_t i = 0; i < data.length(); ++i )
	{
		std::cout << "character at index " << i << ": " << data.at( i ) << "\n";
	}
}
 
Ok, vielen Dank für deine Hilfe!

ich versteh das noch nicht ganz.
Muss ich jetzt nicht mehr bis eof lesen?
Macht das diese Zeile hier?
Code:
std::string data( ( std::istreambuf_iterator< char >( in ) ), std::istreambuf_iterator< char >() );

ist es eigentlich egal ob ich ios oder ios_base nehme?

nochmal danke
 
Zuletzt bearbeitet:
Als aller erstes analysiert man dann auch mal die gegebene Datei anstatt einfach Zeichenweise einzulesen.

Für Zeichenweises einlesenund dann konkatenieren bietet sich übrigens auch ein stringstream an. Die Standard-Konkatenation von Strings in C++ ist aber manchmal auch ausreichend. Der Stringstream bietet mehr darüber hinaus.

Eventuell bietet sich auch eine streambasierte Einlesemethode an die in entsprechende char-Arrays speichert die du auch über einen char* dann nutzen kannst, ähnlich einem string.

Werde dir erstmal klar was du tun willst und warum du dich für einen bestimmten Datentyp entscheiden möchtest. Nach diesen Überlegungen, analysiere die Struktur deiner Textdatei und entscheide danach.

Wie antred schon gesagt hat, durch die Überladung des string-Datentyps mit dem []-Operator kannst du auch auf die einzelnen Bytes eines Strings zugreifen. Die .at() Methode bietet ähnliches, afaik aber mit Speicherbereichsprüfung und demnach oft vorzuziehen ;)
 
Und für den optimalen Lerneffekt, sagen wir dir jetzt noch, was an deinem Originalcode verkehrt ist. ;)

Code:
std::fstream file_stream;
 
std::vector<char> data;
std::vector<char>::iterator count;
count = data.begin();
 
file_stream.open("Test.txt", std::ios::in | std::ios::app)

// Du solltest nach dem Öffen noch prüfen, ob die Datei tatsächlich geöffnet werden konnte.
// if ( ! file_stream )
// {
//     std::cerr << "Aaaaah, hilfe!!!\n";
//     return 1;
// }
//
 
while (!file_stream.eof())
{
	// __FEHLER__!!! data.size() wird hier immer 0 zurückgeben, denn du hast oben einen leeren vector angelegt und diesen nie mit
	// irgend was befüllt. Wenn du das tatsächlich mit diesem Code lösen wolltest, müßtest du erst mal ermittlen, wieviele Zeichen
	// deine Datei eigentlich enthält. Dann müßtest du dafür sorgen, daß dein vector auch groß genug ist, um all diese Zeichen
	// aufzunehmen. Das geht mit std::vector::resize().
	// Des weiteren darfst du natürlich nicht immer wieder a Index 0 schreiben, sonst wirst du ja ab dem 2. Durchlauf dieser while-
	// Schleife die ersten bereits gelesenen Zeichen wieder überschreiben.
	file_stream.read(&data[0], data.size());
	std::cout << data.at(*count) << std::endl;
	
	// Das ist zwar nicht verkeht, aber du solltest wissen, daß count++ (Postinkrement) ineffizienter sein kann als ++count (Präinkrement).
	// Wo immer möglich, solltest du dem Präinkrement den Vorzug geben ... also erst das ++ und dann der Variablenname.
	count++;
}
 
Zuletzt bearbeitet:
Anmerkung zur Korrektur: Das weitere Flag std::ios::app ist beim Lesen nicht notwendig da es dort keinen append-mode in dem Sinne gibt.
 
Zephyro schrieb:
ich versteh das noch nicht ganz.
Muss ich jetzt nicht mehr bis eof lesen?
Macht das diese Zeile hier?

In der Zeile erstellen wir ein std::string-Objekt. std::string bietet mehrere verschiedene Konstrukoren. Einer von diesen erlaubt es uns, 2 Input-Iteratoren anzugeben. Wir verknüpfen den ersten Inputiterator mit dem ifstream-Objekt Namens in. Den 2. lassen wir sozusagen "leer". Für den Konstruktor des std::string-Objekt bedeutet dies so viel wie

"Bitte befülle diesen String, indem du über den dir übergebenen Input-Iterator aus dem ifstream-Objekt so lange Zeichen liest, bis du EOF erreichst.

Zephyro schrieb:
ist es eigentlich egal ob ich ios oder ios_base nehme?

Hmmm, das weiß ich jetzt ehrlich gesagt nicht. Ich nehme immer ios_base, aber wahrscheinlich macht das keinen Unterschied.
 
@Keepers

Ja hast recht, ich muss mir die String und Vector -objekte nochmal genauers anschauen, wie gesagt kenne die beiden noch fast nicht. ;)

Das ios::app ist nur drin, weil ich vorher copy & paste gemacht habe. In dem Programm habe ich noch eine methode zum schreiben drin, deshalb ist des noch ausversehen reingerutscht^^.

@antred

Danke für die Fehlerkorrektur und die Erklärung zu den Konstruktoren. Hat mir sehr weitergehofen ;)
Ich schau mir das ganze noch in ruhe an und falls ich dann noch Fragen haben sollte, melde ich mich wieder hier.

mfg Zephyro
Ergänzung ()

Hey,

angenommen ich habe jetzt noch andere Dateien die ich einlesen möchte z.B. jpg oder pdf, kann man das genauso ohne weiteres lesen?
Ich habs mit jpg schon versucht, dann bekomme ich die entsprechenden Zeichen in die Console geschrieben und zusätzlich noch ein piependes Geräusch vom PC.

Das das Bild Zeichen ausspuckt ist logisch und das der Inhalt der pdf wahrscheinlich nicht im Klartext lesbar ist auch.
Ich möchte in einer weiteren Ausbaustufe des Programmes, die Dateien verschlüsseln - deshalb die Frage...

gibts noch weitere möglichkeiten die Daten einzulesen? ios_base::binary hab ich versucht, aber da kommt das piepen (aber nur wenn ich die Daten des Bildes auf die Console schreiben lasse ) .

Ist das mit ios_base::binary richtig?
 
Zuletzt bearbeitet:
Zephyro schrieb:
gibts noch weitere möglichkeiten die Daten einzulesen?
Nicht wirklich, außer du willst die WinAPI (CreateFile) oder C-Funktionen (fopen) nutzen.
Zephyro schrieb:
ios_base::binary hab ich versucht, aber da kommt das piepen (aber nur wenn ich die Daten des Bildes auf die Console schreiben lasse ) .
Das Piepen ist normal, lass dir mal 0x07 auf der Konsole ausgeben.
Zephyro schrieb:
Ist das mit ios_base::binary richtig?
Wenn der Inhalt der Dateien nicht in Textform vorliegt, dann ist das schon richtig.
 
jpg, pdf etc. sind alles binärformate. dort wird als byte-strom abgelegt (dadurch zB auch wahlfreier zugriff).

Das einlesen und interpretieren über den ASCII Code führt dann natürlich zu imposanten Ergebnissen.

Further on: In einer Txt-Datei legst du die Zahl 4 als Character ab. In der Binary werden dafür standardmäßig 4 Bytes reserviert und dann auch reingeschrieben.

Im binary mode kannst du dir den kram holen wie du möchtest, du kannst aus dem byte-strom gleich einen integer rausziehen, oder byteweise, oder du ziehst dir ein long raus. Das Ergebnis ist die Interpretation des Datentyps anhand der gelesenen Bytes. Deshalb ist es ja so entscheidend dass man sich vorher Gedanken darüber macht wie die Datei aussieht und sich Standards entwickelt haben ;-)

Hast du das mal verstanden und einige Male angewendet wirst du feststellen wie schnell man sich manchmal mit ein paar Zeilen Code ein Problem selbst lösen kann.

In meiner Forschungsarbeit arbeite ich mit Sprachanalysen und Mustererkennung, mein Trainingsmaterial war aber nicht als reines Audio abgelegt, sondern in einem Container-Format (ähnlich wie wav). Dort waren Sprachtranskriptionen und viele Infos vorangestellt.
Kurzer Blick in den Standard, schon gewusst an welcher Byte stelle steht wo das Audio beginnt. 20 Zeilen Code später und ne Schleife drumrum haben sich knapp 10.000 Files selbst extrahiert ohne dass ich dafür erst im Netz nach irgendeiner dämlichen Freeware suchen musste etc.

Was ich damit sagen will ist, man kann immer danach suchen ob ein Problem schon gelöst ist. Aber am effizientesten ist es, wenn man solche kleinen Probleme auf Grund seiner Fähigkeiten schneller löst als man durch 10 Google-Seiten durchgelaufen ist um festzustellen dass das exotische phondat-Format gar nicht in den ganzen Tools bekannt ist.
 
Zurück
Oben