ich will mit einer Schleife eine Datei mit fstream einlesen.
In dem Testfile steht nur der Satz "Das ist das Testfile."
Dabei gehe ich die Schleife einmal zu viel durch. Warum?
./a.out
Das0 ist1 das2 Testfile.3 Testfile.4
René D. schrieb:> ich will mit einer Schleife eine Datei mit fstream einlesen.> In dem Testfile steht nur der Satz "Das ist das Testfile.">> Dabei gehe ich die Schleife einmal zu viel durch. Warum?
Weil C++ nicht versucht in die Zukunft zu sehen.
EOF wird erst dann wahr, wenn ein Leseversuch gescheitert ist. D.h. du
musst mit dem Ergebnis des Leseversuchs die Schleife steuern, bzw. den
Stream nach dem Leseversuch befragen, ob er noch ok ist. Alle
Stream-Lese-Operationen sind so ausgelegt, dass man sie immer dafür
benutzen kann.
wäre die PASCAL-Variante. Funktioniert aber aus dem gleichen Grund nicht
in C++, weil eben C++ eine Datei erst dann als vollständig abgearbeitet
ansieht, wenn es nicht mehr daraus lesen kann.
eof() ist in C++ eine Funktion, die man hinterher bemüht um
festzustellen, warum die Leseschleife abgebrochen wurde (was, wie du ja
jetzt weißt, identisch ist mit: es konnte nicht mehr gelesen werden).
Wurde die Schleife wegen eof abgebrochen, dann ist alles in Ordnung.
Wenn nicht, dann ist irgendetwas anderes passiert. Zb hat jemand die CD
aus dem Laufwerk genommen, die Netzwerkverbindung ist abgerissen, das
Bluetoothmodul hat den Funkkontakt verloren, Lesefehler auf der
Festplatte, der stream ist auf die Konsole geroutet und der Benutzer hat
Ctrl-Z eingetippt, etc. etc. Es gibt viele Möglichkeiten warum eine
Leseoperation schief gehen kann. EOF ist nur eine Möglichkeit davon.
1
while(filestr>>s)
2
{
3
cout<<s<<i++<<' ';
4
}
5
6
if(!filestr.eof())
7
cout<<"ein unbekannter Fehler passierte beim Lesen der Datei\n";
Und nicht vergessen.
In C++ gibt es nur das allgemeine Konzept eines Streams. Ein Stream kann
aber vieles sein. Der kann mit einem File verknüpft sein, der kann per
Netzwerk auf ein File auf einem Server führen, der kann aber auch von
der Eingabekonsole lesen. Woher soll denn ein Stream wissen, ob ein
Benutzer noch was tippen will? Auf manchen Systemen ist es sogar
möglich, dass ein anderer Prozess etwas in die Datei schreibt, während
du sie liest. Durch Input Redirection auf der Shell ist es auch möglich,
dass das was du als File ansiehst in Wirklichkeit ganz was anderes ist,
etc. etc.
Daher dieses plakative, leicht merkbare "C++ versucht nicht in die
Zukunft zu sehen". Erst beim Versuch aus dem Stream zu lesen entscheidet
sich, ob das geht oder nicht und man kann sich hinterher ansehen, ob die
Operation geklappt hat oder nicht und wenn nicht - warum nicht.
Danke Karl Heinz für deine ausführliche Erläuterung. Das interessanteste
ist, dass filestr zwei Sachen hat. Es wirft etwas in den String und hat
auch einen Rückgabewert, den ich als Indikator für die While Schleife
nutzen kann.
Der Stream wird sich in meinem Fall auf Fileoperationen beschränken.
Ich will mir einen Parser und/oder einen Beautifier schreiben.
René D. schrieb:> Danke Karl Heinz für deine ausführliche Erläuterung. Das interessanteste> ist, dass filestr zwei Sachen hat. Es wirft etwas in den String und hat> auch einen Rückgabewert, den ich als Indikator für die While Schleife> nutzen kann.
:-)
Wenn du mal ganz genau dir die Member der Stream Klassen ansiehst, dann
wirst du merken, dass diese einen operator bool bzw. einen operator !
besitzen. Genau die sind es, de es dir ermöglichen ein Stream Objekt in
einer Abfrage zu benutzen.
Und da ein >> das stream Objekt als Returnwert hat, funktionieren dann
so Dinge wie
while( fstr >> i )
das ist im Grunde nichts anderes als
while( fstr.operator>>(i).operator bool() )
(wenn du mir die nicht ganz korrekte Schreibweise der operator Aufrufe
erlaubst)
> Der Stream wird sich in meinem Fall auf Fileoperationen beschränken.
Das hab ich schon so verstanden. C++ ist aber so aufgebaut, dass sich
alles auf den kleinsten gemeinsamen Nenner stützt, welcher 'stream'
heißt und nach Möglichkeit alles in dieses allgemeine Stream-Konzept
eingebunden wird. Und daher ist diese Systematik so gestaltet, dass sich
so gut wie alles darin abbilden lässt. Dies ist wiederrum wichtig, damit
man die Dinge aus std::algorithm auch auf streams (ohne Ansehen des
speziellen streams) anwenden kann.
Karl Heinz Buchegger schrieb:> :-)> Wenn du mal ganz genau dir die Member der Stream Klassen ansiehst, dann> wirst du merken, dass diese einen operator bool bzw. einen operator !
alles in dieses allgemeine Stream-Konzept
> eingebunden wird. Und daher ist diese Systematik so gestaltet, dass sich> so gut wie alles darin abbilden lässt. Dies ist wiederrum wichtig, damit> man die Dinge aus std::algorithm auch auf streams (ohne Ansehen des> speziellen streams) anwenden kann.
Karl Heinz hast du noch einen Tipp,
wie man einen eigenen Manipulator schreibt?
Ich habe in meinen Büchern nur die Anwendung von vorhanden Manipulatoren
gefunden.
Ich will mehrere Textfiles nacheinader parsen und Informationen aus den
Headern sammeln. Es sind alles String Operationen, deshalb will ich auch
kein Template nutzen.
ostream& find_entry(ostream &os) { return cut(find(&os));
Die Stream könnten eine feine Sache sein. Man muss eben doch wieder ein
paar Randbedingungen wissen, die nicht so leicht auffindbar sind.
1
#include<iostream>
2
3
usingnamespacestd;
4
5
intmain(){
6
7
cout<<cin;
8
return0;
9
}
Ich will die Pipeline in Linux ausnutzen. Das File läuft schon.
./a.out |ls
ahb_sseg.vhd a.out bea.cc~ include.h myexcept.h outfile.cpp~
outfile.hpp~ out.txt test_pipe.cpp
Nur wenn die Pipeline leer ist, kommt ein Hexwert.
./a.out
0x601050red@linux-nrd1:~
Auf was muss ich cin testen?
René D. schrieb:> Ich will die Pipeline in Linux ausnutzen. Das File läuft schon.
Nein.
> ./a.out |ls
Damit übergibst du die Ausgabe von a.out an ls, das sich dafür aber
nicht interessiert. ls schreibt dann seine Ausgabe direkt in dein
Terminal.
> Nur wenn die Pipeline leer ist, kommt ein Hexwert.
Der kommt immer, weil cin für die Operation in einen Zeiger konvertiert
wird, dessen Wert dann ausgegeben wird. Im ersten Fall siehst du den nur
nicht, weil er in die Pipe an ls geschoben und nicht ausgegeben wird.
Versuch's mal mit
1
ls | ./a.out
So wie du dir das vostellst, funktioniert das nicht. Das muß eher so
aussehen:
Das Programm war so schon kurz. Eigentlich schon genial.
Es mir schon peinlich, dass es nicht läuft. Ich muss zur meiner
Entschuldigung dazu sagen ich, ich habe mehr mit hardwarenahem C zu tun.
Man, jetzt muss ich den Flow noch kontrollieren.
Ich will die gelisteten Files (durch ls generiert) nacheinander öffnen
und mit einem Parser eine Liste von dem Inhalt der Files erstellen.
Die Files werden immer mehr und von Hand alles zu synchronisieren wird
immer aufwendiger. Deshalb will ich mir ein Tool schreiben.
Rolf Magnus schrieb:> So wie du dir das vostellst, funktioniert das nicht. Das muß eher so> aussehen:>>
1
>#include<iostream>
2
>
3
>usingnamespacestd;
4
>
5
>intmain()
6
>{
7
>charc;
8
>while(cin.get(c))
9
>{
10
>cout.put(c);
11
>}
12
>return0;
13
>}
14
>
Ich habe den Programm mal ausprobiert. der Output kommt nur es beendet
sich nicht. Als würde es noch auf eine Eingabe warten.
Erst wenn ich von Hand was eingebe wird es beendet.
René D. schrieb:> Ich habe den Programm mal ausprobiert. der Output kommt nur es beendet> sich nicht.
Tut es bei mir. Sowohl wenn ich die Ausgabe von ls per Pipe reinschicke,
als auch wenn ich eine Datei reinschiebe. Die Schleife müßte bei einem
EOF abbrechen. Wie hast du es denn genau probiert?
> Wäre es dann nicht einfacher gleich die Files/Directories mit der> passenden API zu lesen? (z.B.> http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm )
die Boost lib habe ich noch nicht durchschaut. Und die Fehlermeldungen
sind im Fehlerfall immer so groß.
Ich habe gerade das Beispiel simple_ls.cpp mal compiliert. Lief so weit.
Normalerweise nutze ich Shell scripte, nun wollte ich die Shell scripte
in den C/C++ Code verlagern, Da ich hier sowie so was programmieren
muss. Zusätzlich wollte ich es elegant manchen und hatte mir hier was
erhofft, das so scheinbar nicht geht.
Werde mal weiter forschen und mich dann entscheiden.
René D. schrieb:> Zusätzlich wollte ich es elegant manchen und hatte mir> hier was erhofft, das so scheinbar nicht geht
Es gibt ja noch viele andere (Skript)Sprachen, die so etwas schon können
(Dateiverarbeitung etc...), C++ ist in der Hinsicht schon recht
spartanisch.
René D. schrieb:> die Boost lib habe ich noch nicht durchschaut. Und die> Fehlermeldungen sind im Fehlerfall immer so groß.
Hat aber nix mit boost direkt zu tun, sondern ist eher C++ spzifisch.
Und wenn man sich mit einer Sache nicht beschäftig, wird es auch nicht
besser ;-)
Was eigenes mag erstmal einfach erscheinen, aber spätestens wenn jemand
in seiner Konfig z.B. ein anderes ausgabeformat als default für 'ls'
einstellt geht der Stress los...