 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Ernst Baumann Guest
|
Posted: Wed Nov 01, 2006 5:19 pm Post subject: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Hallo allerseits,
mir wurde geraten bei Dateizugriffen nach folgender Methode Fehler zu
behandeln (siehe unten Fehlerreport).
Beispiel: (Compiler: MS VC++ 6.0)
---------- Programmbeginn -------------
#include "stdafx.h"
#include <iostream> // i/o
#include <fstream> // datei i/o
using namespace std;
int main(){
fstream quelle;
int z1, z2;
int zahl;
quelle.open("C:\\test.txt", ios::out|ios::app);
quelle.close();
quelle.open("C:\\test.txt",ios::in|ios::out|ios::trunc|ios::binary);
// Testdaten anlegen
z1= 110;
z2= 111;
quelle << z1;
quelle << ' ';
quelle << z2;
// zum Testen:
// quelle << "a";
quelle.seekg(0,ios::beg);
while(quelle >> zahl){
cout << zahl << endl;
}
// Jetzt Fehlerreport
if (!quelle.eof()){
if (quelle.bad())
cout << "Es gab ein technisches Problem\n"; // (*)
else
cout << "Format-Fehler!\n";
}
return(0);
}
---------- Programmende -------------
Wenn _vor_ Erreichen des Dateiendes ein Fehler gemacht wird, wird die
while-Schleife verlassen und der Fehler ausgegeben. So weit so gut.
Was passiert aber, wenn beim Erreichen des Dateiendes, d.h. wenn die
letzte Zahl ausgelesen wird und damit der Dateizeiger auf das
Dateiende geht (d.h. eofbit = 1) z.B. ein Formatfehler auftritt (das
letzte ausgelesene Gebilde könnte z.B. keine Zahl sein, sondern ein
Buchstabe). Dann würde dieser Formatfehler nicht ausgegeben.
Oder taucht dieser Fall nie auf, weil nach dem Auftreten des
Formatfehlers das Dateiende gar nicht mehr eingelesen wird?
Ich konnte den Fall eofbit=1 und failbit=1 nicht gleichzeitig
produzieren.
Fängt man also mit diesem Fehlerreport die Fehler ab?
mfg
Ernst |
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Wed Nov 01, 2006 8:25 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Ernst Baumann wrote:
| Quote: | Was passiert aber, wenn beim Erreichen des Dateiendes, d.h. wenn die
letzte Zahl ausgelesen wird und damit der Dateizeiger auf das
Dateiende geht (d.h. eofbit = 1) z.B. ein Formatfehler auftritt (das
letzte ausgelesene Gebilde könnte z.B. keine Zahl sein, sondern ein
Buchstabe). Dann würde dieser Formatfehler nicht ausgegeben.
|
Das passiert nicht. Das eof-Bit wird erst gesetzt, wenn man versucht, über
das Ende der Datei hinauszulesen. Beim letzten Byte gibt's also noch kein
EOF. |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Thu Nov 02, 2006 12:58 am Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Rolf Magnus wrote:
| Quote: | Ernst Baumann wrote:
Was passiert aber, wenn beim Erreichen des Dateiendes, d.h. wenn die
letzte Zahl ausgelesen wird und damit der Dateizeiger auf das
Dateiende geht (d.h. eofbit = 1) z.B. ein Formatfehler auftritt (das
letzte ausgelesene Gebilde könnte z.B. keine Zahl sein, sondern ein
Buchstabe). Dann würde dieser Formatfehler nicht ausgegeben.
Das passiert nicht. Das eof-Bit wird erst gesetzt, wenn man versucht, über
das Ende der Datei hinauszulesen. Beim letzten Byte gibt's also noch kein
EOF.
|
Doch:
int
main()
{
std::istringstream in( "-3.5e" ) ;
double d;
int zahl = 0 ;
while ( in >> d ) {
++ zahl ;
}
if (!quelle.eof()){
if (quelle.bad())
std::cout << "Es gab ein technisches Problem\n"; // (*)
else
std::cout << "Format-Fehler!\n";
}
std::cout << zahl << " gelesen\n" ;
return 0 ;
}
Leiter gibt es keine 100% sichere Möglichkeit, Fehler zu
überprüfen.
--
James Kanze (Gabi Software) email: james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Ernst Baumann Guest
|
Posted: Thu Nov 02, 2006 7:20 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
| Quote: | int
main()
{
std::istringstream in( "-3.5e" ) ;
double d;
int zahl = 0 ;
while ( in >> d ) {
++ zahl ;
}
if (!quelle.eof()){
if (quelle.bad())
std::cout << "Es gab ein technisches Problem\n"; // (*)
else
std::cout << "Format-Fehler!\n";
}
std::cout << zahl << " gelesen\n" ;
return 0 ;
}
Leiter gibt es keine 100% sichere Möglichkeit, Fehler zu
überprüfen.
Kannst du mir erklären, was folgende Zeile macht?
std::istringstream in( "-3.5e" ) ;
Welche Indlude-Dateien muss ich vor int main mit |
#include
einfügen?
mfg
Ernst |
|
| Back to top |
|
 |
Ernst Baumann Guest
|
Posted: Thu Nov 02, 2006 9:05 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
| Quote: |
Leiter gibt es keine 100% sichere Möglichkeit, Fehler zu
überprüfen.
Nochmals ein paar Fragen zu meinem letzten Programm-Beispiel: |
1)
while(quelle >> zahl){
cout << zahl << endl;
}
Wann liefert der Operator >> false (bzw. 0) zurück?
In der Datei steht ja:
110 111
Wenn 111 ausgelesen wird, wird dabei auch das Dateiende erreicht und
auch eof ausgelesen. D.h. durch
quelle >> zahl (--> 111)
wird das Dateiende erreicht und die Bedingung quelle >> zahl wird
dabei true.
Und erst beim zweiten Auslesen des eof wird dann die Bedingung
quelle >> zahl
false (dabei wird dann _nur_ eof ausgelesen).
Das heisst, dass die Bedingung
quelle >> zahl
nur dann false wird, wenn _nur_ eof ausgelesen wird.
Ist das korrekt?
2)
Beim erstmaligen Auslesen des eof (durch quelle >> zahl (-->111))
wird zwar die Bedingung quelle >> zahl noch true, doch das eofbit
bekommt dann den Wert 1. D.h. mann muss dann unbedingt
quelle.clear()
machen, um weiterhin Dateizugriffe machen zu können.
Ist das richtig?
mfg
Ernst |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Fri Nov 03, 2006 8:01 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Ernst Baumann wrote:
| Quote: | int
main()
{
std::istringstream in( "-3.5e" ) ;
double d;
int zahl = 0 ;
while ( in >> d ) {
++ zahl ;
}
if (!quelle.eof()){
if (quelle.bad())
std::cout << "Es gab ein technisches Problem\n"; // (*)
else
std::cout << "Format-Fehler!\n";
}
std::cout << zahl << " gelesen\n" ;
return 0 ;
}
Leiter gibt es keine 100% sichere Möglichkeit, Fehler zu
überprüfen.
Kannst du mir erklären, was folgende Zeile macht?
std::istringstream in( "-3.5e" ) ;
|
Ich richte einen Strom ein, die aus einer Zeichenkette liest. Er
funktionniert genau wie cin oder ein ifstream, nur holt er die
Zeichen aus der gegebenen Zeichenkette.
Hast du eine Datei, die genau dieselben Zeichen enthält, hast du
genau dasselbe Problem: am Ende wird gesagt, dass alles
erfolgreich gelesen wurde, obwohl es eindeutig einen
Formattierungsfehler gegeben hat. (Nur ist es unter Umständen
schwierig, eine Text-Datei ohne '\n' am Ende herzustellen.)
| Quote: | Welche Indlude-Dateien muss ich vor int main mit
#include
einfügen?
|
<sstream> (aber auch <istream>, mindestens formell).
--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Fri Nov 03, 2006 8:19 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Ernst Baumann wrote:
| Quote: | Leiter gibt es keine 100% sichere Möglichkeit, Fehler zu
überprüfen.
Nochmals ein paar Fragen zu meinem letzten Programm-Beispiel:
1)
while(quelle >> zahl){
cout << zahl << endl;
}
Wann liefert der Operator >> false (bzw. 0) zurück?
|
Wenn er auf irgendeinem Grund die Zahl nicht gelesen können hat.
| Quote: | In der Datei steht ja:
110 111
Wenn 111 ausgelesen wird, wird dabei auch das Dateiende erreicht und
auch eof ausgelesen.
|
Kein Problem. cout.eof() wird wohl wahr, aber cout.eof() wird
bei der Umwandlung nicht im Betracht genommen. (cout.eof()
heißt in diesem Fall nur, dass die nächste Eingabe nicht
gelingt. !cout.eof(), dagegen, sagt uns nichts.)
| Quote: | D.h. durch
quelle >> zahl (--> 111)
wird das Dateiende erreicht und die Bedingung quelle >> zahl wird
dabei true.
|
Die Bedingung bleibt wahr. Ob Dateiende erreicht wird oder
nicht. Die Bedingung wird erst dann falsch, wenn überhaupt
keinen Wert gelesen werden kann.
| Quote: | Und erst beim zweiten Auslesen des eof wird dann die Bedingung
quelle >> zahl
false (dabei wird dann _nur_ eof ausgelesen).
|
Nicht genau. Der Regel ist ein bisschen anders.
In der Tat wird der Zustand durch drei boole'sche Werte
dargestellt: eofbit, failbit und badbit. Sofort der Dateiende
gesehen, egal wie oder wann, wird eofbit gesetzt. (Die Bedingung
aber betrachtet nur failbit und badbit.) Beim Anfang eines
Lesens wird als alles erste geprüft, ob alle Bits null sind, und
wann nicht, wird failbit gesetzt, ohne den geringsten Versuch,
etwas zu lesen. In Allgemein: ist eofbit gesetzt, soll der Strom
das Lesen nicht weiter versuchen.
| Quote: | Das heisst, dass die Bedingung
quelle >> zahl
nur dann false wird, wenn _nur_ eof ausgelesen wird.
Ist das korrekt?
|
Fast. Wie oben erklärt, wird ehe gespeichert, dass EOF
ausgelesen wurde, und diesen Zustand getestet.
Auch, alle >> Operatoren fängen an, Leerzeichen zu lesen. Falls
das erste nicht Leerzeichen EOF ist, wird dann auch eofbit und
failbit gesetzt. In den meisten Fällen haben dazu die Daten ein
Format, also bei int, [+-]?[0-9][0-9]*. Wenn man keine
zupassenden Daten lesen kann, wird auch failbit gesetzt.
Die genauen Regeln sind oft komplex. Aber das allegemeine
Problem besteht darin, dass ich in gewissen Fällen bis zum
Dateiende lesen muss, um diesen Formatfehler zu erkennen. Wenn
ich aber Dateiende gelesen habe, wird eofbit gesetzt, und wenn
beide eofbit und failbit gesetzt sind, sieht es genau wie bei
einem fehlerfreien Dateiende aus.
| Quote: | 2)
Beim erstmaligen Auslesen des eof (durch quelle >> zahl (-->111))
wird zwar die Bedingung quelle >> zahl noch true, doch das eofbit
bekommt dann den Wert 1. D.h. mann muss dann unbedingt
quelle.clear()
machen, um weiterhin Dateizugriffe machen zu können.
Ist das richtig?
|
Wenn es noch Daten gibt. Normallerweise gibt es auch keinen.
(Man kann es aber tun, wenn erwartet wird, dass die Datei noch
wächst.)
--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Ernst Baumann Guest
|
Posted: Sun Nov 05, 2006 11:31 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
| Quote: |
Kein Problem. cout.eof() wird wohl wahr, aber cout.eof() wird
bei der Umwandlung nicht im Betracht genommen. (cout.eof()
heißt in diesem Fall nur, dass die nächste Eingabe nicht
gelingt. !cout.eof(), dagegen, sagt uns nichts.)
Eine Frage: |
eof() ist doch eine Methode. Eine Methode gehört doch zu einem Objekt.
cout ist aber kein Objekt. Was ist dann cout.eof() für ein Konstrukt?
Ist cout eine Klasse und damit cout.eof() eine Klassenmethode?
| Quote: |
Wenn es noch Daten gibt. Normallerweise gibt es auch keinen.
(Man kann es aber tun, wenn erwartet wird, dass die Datei noch
wächst.)
Ich meinte damit nur: |
Wenn das eofbit=1 gesetzt wurde, liefert good()=1 zurück.
Wenn man dann nochmals auf die Datei zugreifen will, muss vorher
clear() gemacht werden.
Ist das korrekt?
--------------------------------------------------------------------
Um zu überprüfen, ob ich dich richtig verstanden habe, fasse ich alles
nochmals in meinen Worten zusammen:
1)
Wird aus einer Datei etwas gelesen (egal mit welcher Funktion oder
Methode), werden zuerst die 3 Bits eofbit, failbit und badbit
überprüft. Wenn good() den Wert 1 zurückgibt (d.h. mindestens ein Bit
dieser 3 Bits ist gesetzt), dann wird gar nichts gelesen, sondern
failbit=1 gesetzt.
2)
Wenn good() den Wert 0 zurückgibt, wird aus der Datei gelesen. Wenn
dabei das Dateiende erreicht wird, wird dann (nach dem Lesen) eofbit
auf 1 gesetzt (damit wird dann good() auch 1) und bei einem erneuten
Leseversuch wird dann nichts gelesen, sondern (siehe 1)) failbit=1
gesetzt.
Aus 1) und 2) folgt, dass man also beim Lesen lauter korrekter Zahlen,
wie (z.B. -3.5e3), die jeweils durch ein Leerzeichen getrennt sind, am
Schluss eofbit=1 und failbit=1 wird.
3)
Beim Lesen einer nichtkorrekten Zahl (z.B. nur -3.5e soll in einer
Datei stehen), wird das Dateiende erreicht. Außerdem wurde eine
nichtkorrekte Zahl gelesen (nach e fehlt eine Zahl). Deshalb wird
eofbit=1 und failbit=1.
Ergebnis:
Es ist programmtechnisch nicht möglich, herauszubekommen (d.h. zu
unterscheiden), ob alle Daten einer Datei korrekt ausgelesen werden
konnten (d.h. ohne Formatfehler) oder ob beim Lesen des _letzten_
Bytes einer Datei ein Fehler (Formatfehler) aufgetreten ist.
Ist das richtig?
Bemerkungen:
a) Wenn in einerDatei nur Leerzeichen stehen und man liest diese
Leerzeichen z.B. mit
quelle >> myarray aus, dann wird eofbit=1 und failbit=1 gesetzt.
Ist das richtig?
b) Wenn aus einer "leeren" Datei (d.h. eine Datei mit 0 Bytes) etwas
gelesen wird, dann wird eofbit=1 und failbit=1 gesetzt.
Ist das richtig?
Hast du das gemeint mit:
| Quote: | Sofort der Dateiende gesehen, egal wie oder wann, wird eofbit gesetzt.
(Die Bedingung aber betrachtet nur failbit und badbit.)
|
mfg
Ernst |
|
| Back to top |
|
 |
Jörg Barfurth Guest
|
Posted: Mon Nov 06, 2006 6:06 am Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Hallo Ernst,
Ernst Baumann schrieb:
| Quote: | Kein Problem. cout.eof() wird wohl wahr, aber cout.eof() wird
bei der Umwandlung nicht im Betracht genommen. (cout.eof()
heißt in diesem Fall nur, dass die nächste Eingabe nicht
gelingt. !cout.eof(), dagegen, sagt uns nichts.)
Eine Frage:
eof() ist doch eine Methode. Eine Methode gehört doch zu einem Objekt.
cout ist aber kein Objekt.
|
Doch. cout, clog, cerr und cin sind vordefinierte,globale Objekte.
| Quote: | Was ist dann cout.eof() für ein Konstrukt?
|
Ein Methodenaufruf.
| Quote: | Ist cout eine Klasse und damit cout.eof() eine Klassenmethode?
|
Nein. In Ausdrücken der Form expr.member, muss expr immer ein
Objektausdruck sein. Wenn du über die Klasse auf ein statisches Member
zugreifen willst, schreibt sich das Klasse::member.
| Quote: | Wenn es noch Daten gibt. Normallerweise gibt es auch keinen.
(Man kann es aber tun, wenn erwartet wird, dass die Datei noch
wächst.)
Ich meinte damit nur:
Wenn das eofbit=1 gesetzt wurde, liefert good()=1 zurück.
|
Nein. good gibt bool zurück, und wenn eofbit in rdstate() gesetzt ist,
dann liefert good() false zurück.
[Bei Konvertierung in Integer ergibt false->0]
| Quote: | Wenn man dann nochmals auf die Datei zugreifen will, muss vorher
clear() gemacht werden.
Ist das korrekt?
|
Ja. Und ein Positionswechsel oder Anfügen weiterer Daten.
| Quote: | --------------------------------------------------------------------
Um zu überprüfen, ob ich dich richtig verstanden habe, fasse ich alles
nochmals in meinen Worten zusammen:
1)
Wird aus einer Datei etwas gelesen (egal mit welcher Funktion oder
Methode), werden zuerst die 3 Bits eofbit, failbit und badbit
überprüft. Wenn good() den Wert 1 zurückgibt (d.h. mindestens ein Bit
dieser 3 Bits ist gesetzt),
|
Du meinst: ...wenn good() den Wert false zurückgibt...
| Quote: | dann wird gar nichts gelesen, sondern
failbit=1 gesetzt.
|
So korrigiert: ja
| Quote: | 2)
Wenn good() den Wert 0 zurückgibt,
|
Wenn good() den Wert true [der übrigens zu 1 konvertiert] zurückgibt,....
| Quote: | wird aus der Datei gelesen. Wenn
dabei das Dateiende erreicht wird, wird dann (nach dem Lesen) eofbit
auf 1 gesetzt (damit wird dann good() auch 1)
|
false
| Quote: | und bei einem erneuten
Leseversuch wird dann nichts gelesen, sondern (siehe 1)) failbit=1
gesetzt.
|
Ja.
| Quote: | Aus 1) und 2) folgt, dass man also beim Lesen lauter korrekter Zahlen,
wie (z.B. -3.5e3), die jeweils durch ein Leerzeichen getrennt sind, am
Schluss eofbit=1 und failbit=1 wird.
|
Ja, wenn du solange weiterliest, bis das Lesen fehlschlägt, und wenn
kein echtes Problem (das badbit setzt) auftritt.
| Quote: | 3)
Beim Lesen einer nichtkorrekten Zahl (z.B. nur -3.5e soll in einer
Datei stehen), wird das Dateiende erreicht.
|
Was meist doppelt inkorrekt ist: bei praktisch allen Textdateiformaten
endet eine korrekte Datei mit einem Zeilenwechsel.
| Quote: | Außerdem wurde eine
nichtkorrekte Zahl gelesen (nach e fehlt eine Zahl). Deshalb wird
eofbit=1 und failbit=1.
Ergebnis:
Es ist programmtechnisch nicht möglich, herauszubekommen (d.h. zu
unterscheiden), ob alle Daten einer Datei korrekt ausgelesen werden
konnten (d.h. ohne Formatfehler) oder ob beim Lesen des _letzten_
Bytes einer Datei ein Fehler (Formatfehler) aufgetreten ist.
Ist das richtig?
|
Ja, bei dieser Methode nicht.
Gruß,
- Jörg |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Mon Nov 06, 2006 3:45 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Jörg Barfurth wrote:
[...]
| Quote: | 3)
Beim Lesen einer nichtkorrekten Zahl (z.B. nur -3.5e soll in einer
Datei stehen), wird das Dateiende erreicht.
Was meist doppelt inkorrekt ist: bei praktisch allen Textdateiformaten
endet eine korrekte Datei mit einem Zeilenwechsel.
|
Vorsicht. Das mag unter Unix stimmen, aber in der Praxis hängt
es stark davon ab, wie die Datei erzeugt wird, und viele
Editore unter Windows screiben häufig Dateien, die nicht mit
einem Zeilenwechsel enden. (Angeblich: ich gebe zu, dass auch
unter Windows benutze ich fast ausschließlich vim, und er endet
alle Dateien mit einem Zeilenwechsel.)
Das wichtige ist aber, dass das Setzen von eofbit vollig
unabhängig aller anderen Überprüfungen stattfindet. Und ins
besonders, dass man allgemeins nicht braucht, bis Dateiende zu
lesen, um Formatfehler zu erkennen. Nur wenn man den Dateiende
sehen muss, um den Formatfehler zu erkennen, gibt es
Mehrdeutigkeit.
--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Ernst Baumann Guest
|
Posted: Tue Nov 07, 2006 10:04 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
| Quote: |
Doch. cout, clog, cerr und cin sind vordefinierte,globale Objekte.
also so was ähnliches wie globale Variablen. Die globalen Objekte sind |
also in sämtlichen Methoden und Funktionen gültig (darauf zugreifbar)..
Stimmt das?
In der Include Datei iostream wird deklariert:
extern _CRTIMP ostream cout;
ostream ist die Klasse, cout das Objekt.
Was ist dann aber: extern _CRTIMP?
| Quote: |
Ich meinte damit nur:
Wenn das eofbit=1 gesetzt wurde, liefert good()=1 zurück.
Nein. good gibt bool zurück, und wenn eofbit in rdstate() gesetzt ist,
dann liefert good() false zurück.
[Bei Konvertierung in Integer ergibt false->0]
Wenn rdstate() einen Wert ungleich 0 zurückgibt, dann liefert good() |
den Wert false zurück.
Stimmt das?
| Quote: |
Wenn man dann nochmals auf die Datei zugreifen will, muss vorher
clear() gemacht werden.
Ist das korrekt?
Ja. Und ein Positionswechsel oder Anfügen weiterer Daten.
Wenn man das nicht machen würde (und z.B. Lesen würde ohne die |
Position, d.h. das Dateiende zu wechseln) dann wäre der Dateizustand
zwar "gecleart" (d.h. goodbit=0, eofbit=0, failbit=0, badbit=0), aber
beim Lesevorgang hätte man dann gleich wieder einen Fehler.
Stimmt das?
Mit dem clear bzw. nicht clear hatte ich noch ein Problem.
Nachdem ich also in meinem Demoprogramm (das aus einer Datei liest)
"-3.5e" nicht in eine Zahl umwandeln konnte (und deshalb eofbit=1 und
failbit=1 wird), habe ich die Datei geschlossen (ohne vorher clear zu
machen) und dann nochmals geöffnet und _sofort_ (d.h. ohne vorher
irgendwelche anderen Aktionen zu machen) eofbit, failbit, badbit
abgefragt. Alle hatten den Wert 1. Warum? Wurden sie nicht durch das
Schließen der Datei automatisch zurückgesetzt?
Wenn das so wäre, müsste man nach dem Öffnen einer beliebigen Datei
zuerst mal clear machen, da die Datei ja in einem Fehlerzustand sein
könnte.
| Quote: |
Aus 1) und 2) folgt, dass man also beim Lesen lauter korrekter Zahlen,
wie (z.B. -3.5e3), die jeweils durch ein Leerzeichen getrennt sind, am
Schluss eofbit=1 und failbit=1 wird.
Ja, wenn du solange weiterliest, bis das Lesen fehlschlägt, und wenn
kein echtes Problem (das badbit setzt) auftritt.
"wenn du solange weiterliest, bis das Lesen fehlschlägt" |
Wie soll man es sonst machen (siehe ganz unten).
| Quote: |
3)
Beim Lesen einer nichtkorrekten Zahl (z.B. nur -3.5e soll in einer
Datei stehen), wird das Dateiende erreicht.
Was meist doppelt inkorrekt ist: bei praktisch allen Textdateiformaten
endet eine korrekte Datei mit einem Zeilenwechsel.
Angenommem in der Datei steht |
-3.5e2
und dann noch ein Leerzeichen.
Wenn man die Datei ausliest mit:
while (quelle >> d )
++zahl;
dann bekommt man wieder am Schluss:
eofbit=1 und failbit=1
Warum ist das doppelt inkorrekt?
(ich habe nicht verstanden, was du damit meinst?)
| Quote: |
Außerdem wurde eine
nichtkorrekte Zahl gelesen (nach e fehlt eine Zahl). Deshalb wird
eofbit=1 und failbit=1.
Ergebnis:
Es ist programmtechnisch nicht möglich, herauszubekommen (d.h. zu
unterscheiden), ob alle Daten einer Datei korrekt ausgelesen werden
konnten (d.h. ohne Formatfehler) oder ob beim Lesen des _letzten_
Bytes einer Datei ein Fehler (Formatfehler) aufgetreten ist.
Ist das richtig?
Ja, bei dieser Methode nicht.
Wie soll man es sonst machen? |
Gibt es überhaupt eine Möglichkeit - bei nicht schwerwiegenden Fehlern
(badbit=1) - einen Formatfehler am Dateiende (der beim Lesen des
letzten Bytes, so wie bei -3.5e) programmtechnisch zu erkennen?
(Ist das bei anderen Programmiersprachen auch so?)
mfg
Ernst |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Tue Nov 07, 2006 11:39 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Ernst Baumann wrote:
| Quote: | Doch. cout, clog, cerr und cin sind vordefinierte,globale Objekte.
also so was ähnliches wie globale Variablen. Die globalen Objekte sind
also in sämtlichen Methoden und Funktionen gültig (darauf zugreifbar).
Stimmt das?
|
Ja.
| Quote: | In der Include Datei iostream wird deklariert:
extern _CRTIMP ostream cout;
ostream ist die Klasse, cout das Objekt.
Was ist dann aber: extern _CRTIMP?
|
Compilermagie. Aller Wahrscheinlichkeit ist das ein Makro, das zu etwas
noch viel abgefahrenerem expandiert. In den Standard-Headern darf der
Compilerhersteller machen, was er will. Da muss kein C++ drin stehen.
Das müssen nicht mal Dateien sein. Der Compiler muss nur sicherstellen,
dass du nach '#include <iostream>' das Objekt 'std::cout' benutzen kannst.
| Quote: | Ich meinte damit nur:
Wenn das eofbit=1 gesetzt wurde, liefert good()=1 zurück.
Nein. good gibt bool zurück, und wenn eofbit in rdstate() gesetzt ist,
dann liefert good() false zurück.
[Bei Konvertierung in Integer ergibt false->0]
Wenn rdstate() einen Wert ungleich 0 zurückgibt, dann liefert good()
den Wert false zurück.
Stimmt das?
|
Genau so ist das definiert.
| Quote: | Wenn man dann nochmals auf die Datei zugreifen will, muss vorher
clear() gemacht werden.
Ist das korrekt?
Ja. Und ein Positionswechsel oder Anfügen weiterer Daten.
Wenn man das nicht machen würde (und z.B. Lesen würde ohne die
Position, d.h. das Dateiende zu wechseln) dann wäre der Dateizustand
zwar "gecleart" (d.h. goodbit=0, eofbit=0, failbit=0, badbit=0), aber
beim Lesevorgang hätte man dann gleich wieder einen Fehler.
Stimmt das?
|
Ja.
| Quote: | Mit dem clear bzw. nicht clear hatte ich noch ein Problem.
Nachdem ich also in meinem Demoprogramm (das aus einer Datei liest)
"-3.5e" nicht in eine Zahl umwandeln konnte (und deshalb eofbit=1 und
failbit=1 wird), habe ich die Datei geschlossen (ohne vorher clear zu
machen) und dann nochmals geöffnet und _sofort_ (d.h. ohne vorher
irgendwelche anderen Aktionen zu machen) eofbit, failbit, badbit
abgefragt. Alle hatten den Wert 1. Warum? Wurden sie nicht durch das
Schließen der Datei automatisch zurückgesetzt?
Wenn das so wäre, müsste man nach dem Öffnen einer beliebigen Datei
zuerst mal clear machen, da die Datei ja in einem Fehlerzustand sein
könnte.
|
Nein, du musst nach dem close() clear() aufrufen, um die Fehlerzustände
wegzuräumen. Eine komplett neu erfolgreich eröffnete Datei
std::ifstream huhu("haha");
hat natürlich keine Fehlerzustände.
| Quote: | 3)
Beim Lesen einer nichtkorrekten Zahl (z.B. nur -3.5e soll in einer
Datei stehen), wird das Dateiende erreicht.
Was meist doppelt inkorrekt ist: bei praktisch allen Textdateiformaten
endet eine korrekte Datei mit einem Zeilenwechsel.
Angenommem in der Datei steht
-3.5e2
und dann noch ein Leerzeichen.
[...]
Warum ist das doppelt inkorrekt?
(ich habe nicht verstanden, was du damit meinst?)
|
Formal muss hinter dem Leerzeichen noch ein '\n' stehen, sonst ist es
keine gültige Textdatei. Praktisch stört das alle mir bekannten Compiler
nicht (allerdings ist kein VMS-Compiler dabei).
| Quote: | Ergebnis:
Es ist programmtechnisch nicht möglich, herauszubekommen (d.h. zu
unterscheiden), ob alle Daten einer Datei korrekt ausgelesen werden
konnten (d.h. ohne Formatfehler) oder ob beim Lesen des _letzten_
Bytes einer Datei ein Fehler (Formatfehler) aufgetreten ist.
Ist das richtig?
Ja, bei dieser Methode nicht.
Wie soll man es sonst machen?
|
Zeilenweise lesen und parsen.
Stefan |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Wed Nov 08, 2006 6:21 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Stefan Reuther wrote:
[...]
| Quote: | 3)
Beim Lesen einer nichtkorrekten Zahl (z.B. nur -3.5e soll in einer
Datei stehen), wird das Dateiende erreicht.
Was meist doppelt inkorrekt ist: bei praktisch allen Textdateiformaten
endet eine korrekte Datei mit einem Zeilenwechsel.
Angenommem in der Datei steht
-3.5e2
und dann noch ein Leerzeichen.
[...]
Warum ist das doppelt inkorrekt?
(ich habe nicht verstanden, was du damit meinst?)
Formal muss hinter dem Leerzeichen noch ein '\n' stehen, sonst ist es
keine gültige Textdatei.
|
Formal ist est implementierungsabhängig, ob die letzte Zeile mit
eine '\n' enden muss oder nicht. Es ist auch
implementierungsabhängig, wie gemappt wird; insbesonders darf
eine Implementierung Sonderzeichen als Seporatoren zwischen
Zeilen benutzen, statt als Zeilende. Am Ende gibt es nur
einiges: die Dokumentation des Compilers zu lesen. Wenn man sie
überhaupt finden kann.
Immerhin gilt das sowieso nur für Dateien (filebuf), und man
kann auch von anderen Sromtypen lesen. In seinem Fall: die Daten
werden angeschaut, so weit wie nötig, um den Ende des Zahls zu
finden. In der Praxis heißt es, ein Zeichen mehr wird
angeschaut. Ist das "Zeichen" ein EOF, wird eofbit gesetzt,
amsonsten nicht. Ist der Formatt falsch, wird failbit gesetzt,
amsonsten nicht. Also, beim Lesen folgender Strings von einem
istringstream:
"-3.5e2 " 0
"-3.5e2" eofbit
"-3.5e " failbit
"-3.5e" eofbit | failbit
" " eofbit | failbit
"" eofbit | failbit
Ersetzt man den ' ' mit einem '\n', bekommt man genau dasselbe
Ergebnis.
Nur die zwei letzten sind tatsächlich Dateiende.
--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Wed Nov 08, 2006 8:03 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Stefan Reuther wrote:
| Quote: | Ernst Baumann wrote:
Doch. cout, clog, cerr und cin sind vordefinierte,globale Objekte.
also so was ähnliches wie globale Variablen. Die globalen Objekte sind
also in sämtlichen Methoden und Funktionen gültig (darauf zugreifbar).
Stimmt das?
Ja.
In der Include Datei iostream wird deklariert:
extern _CRTIMP ostream cout;
ostream ist die Klasse, cout das Objekt.
Was ist dann aber: extern _CRTIMP?
Compilermagie. Aller Wahrscheinlichkeit ist das ein Makro, das zu etwas
noch viel abgefahrenerem expandiert. In den Standard-Headern darf der
Compilerhersteller machen, was er will. Da muss kein C++ drin stehen.
Das müssen nicht mal Dateien sein. Der Compiler muss nur sicherstellen,
dass du nach '#include <iostream>' das Objekt 'std::cout' benutzen kannst.
|
"Nur" ist gut. Er muss insbesondere sicherstellen, dass std::cout auch von
globalen Objekten in deren Konstruktoren schon benutzt werden kann. Es
reicht also nicht, std::cout zu einem normalen globalen Objekt zu machen,
denn dann könnte es sein, dass es schon verwendet wird, bevor es korrekt
initialisiert wurde. Deshalb braucht man hier eine Sonderbehandlung. Und
die wird vermutlich durch dieses Makro ausgelöst. |
|
| Back to top |
|
 |
Stefan Reuther Guest
|
Posted: Wed Nov 08, 2006 11:37 pm Post subject: Re: Wie Fehlerreport machen bei Dateizugriff? |
|
|
Rolf Magnus wrote:
| Quote: | Stefan Reuther wrote:
Ernst Baumann wrote:
Was ist dann aber: extern _CRTIMP?
Compilermagie. Aller Wahrscheinlichkeit ist das ein Makro, das zu etwas
noch viel abgefahrenerem expandiert.[...] Der Compiler muss nur sicherstellen,
dass du nach '#include <iostream>' das Objekt 'std::cout' benutzen kannst.
"Nur" ist gut. Er muss insbesondere sicherstellen, dass std::cout auch von
globalen Objekten in deren Konstruktoren schon benutzt werden kann. Es
reicht also nicht, std::cout zu einem normalen globalen Objekt zu machen,
denn dann könnte es sein, dass es schon verwendet wird, bevor es korrekt
initialisiert wurde. Deshalb braucht man hier eine Sonderbehandlung. Und
die wird vermutlich durch dieses Makro ausgelöst.
|
Dafür gibt's doch std::ios_base::Init, das aus einem mir unerfindlichen
Grund im Standard festgeschrieben ist.
Ich denke eher, _CRTIMP expandiert zu sowas wie __declspec(dllimport),
was man unter Windows braucht, um Symbole aus einer DLL zu importieren
(unter Unixen braucht man nichts besonderes dazu).
Stefan |
|
| Back to top |
|
 |
Powered by phpBB © 2001, 2006 phpBB Group
|