Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Echec IO: on teste errno, comme en C ?

10 réponses
Avatar
Marc Boyer
Bonjour,

je débute avec les fichiers, et je me demandais comment
on faisait pour avoir la cause de l'erreur.

Je fais un
ofstream f("toto.txt");
if (!f.is_open()){
cerr<<"Impossible d'ouvrir toto.txt "<<strerrno(errno)<<endl;
}

Mais est-ce bien la C++-attitude ?

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

10 réponses

Avatar
Michael DOUBEZ
Bonjour,

je débute avec les fichiers, et je me demandais comment
on faisait pour avoir la cause de l'erreur.

Je fais un
ofstream f("toto.txt");
if (!f.is_open()){
cerr<<"Impossible d'ouvrir toto.txt "<<strerrno(errno)<<endl;
}

Mais est-ce bien la C++-attitude ?


En utilisant open() qui est susceptible de lancer une exception à
condition de l'avoir activer avant:
ofstream f;

// Lancer une exception si "failbit" ou "badbit" est levé
f.exceptions (ios::failbit | ios::badbit);

try
{// Open will throw on error
f.open ("toto.txt");
}
catch (exception &e)
{
cerr << "Impossible d'ouvrir toto.txt : " << e.what () << endl;
}

Le contenu du what() dépend de l'implémentation de la STL.

Michael

Avatar
James Kanze
On May 14, 1:32 pm, Marc Boyer
wrote:

je débute avec les fichiers, et je me demandais comment
on faisait pour avoir la cause de l'erreur.

Je fais un
ofstream f("toto.txt");
if (!f.is_open()){
cerr<<"Impossible d'ouvrir toto.txt "<<strerrno(errno)<<endl;
}

Mais est-ce bien la C++-attitude ?


Pourquoi pas ?

Formellement, la situation est exactement pareille qu'en C. La
fonction dit s'il a réussi ou non, mais la norme ne prévoit
aucune indication en ce qui concerne le pourquoi d'un échec.
Tout au plus permet-elle à l'implémentation de modifier errno,
sans pour autant l'exiger ni spécifier des valeurs qu'errno
pourrait éventuellement prendre. La spécification de
filebuf::open se réposant sur la spécification de fopen, dans la
norme C, on pourrait supposer peut-être que le comportement ici
en soit identique, mais je ne suis pas du tout sûr que la norme
C++ l'exige, ni même que c'en était l'intention de l'exiger.

Dans la pratique, sur des plateformes Unix et semblable, et
filebuf::open et fopen vont se réposer sur la fonction Posix
open, et c'est elle qui positionne en fait errno en cas
d'erreur. En revanche, je n'ai malheureusement pas d'expérence
sur ce sujet sous Windows ; je ne saurais donc dire si c'est
aussi le cas là que errno soit positionné. (En renvanche, je
serais très étonné que filebuf::open et fopen se comportent de
manière différente, quelque soit la plateforme.)

--
James Kanze (GABI Software) email:
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

Avatar
James Kanze
On May 14, 2:54 pm, Michael DOUBEZ wrote:

je débute avec les fichiers, et je me demandais comment
on faisait pour avoir la cause de l'erreur.

Je fais un
ofstream f("toto.txt");
if (!f.is_open()){
cerr<<"Impossible d'ouvrir toto.txt "<<strerrno(errno)<<endl;
}

Mais est-ce bien la C++-attitude ?


En utilisant open() qui est susceptible de lancer une exception à
condition de l'avoir activer avant:
ofstream f;

// Lancer une exception si "failbit" ou "badbit" est levé
f.exceptions (ios::failbit | ios::badbit);

try
{// Open will throw on error
f.open ("toto.txt");}

catch (exception &e)
{
cerr << "Impossible d'ouvrir toto.txt : " << e.what () << endl;
}


C'est un peu tordu d'utiliser des exceptions dans ce cas-ci,
non ?

Le contenu du what() dépend de l'implémentation de la STL.


Parmi les quatre auxquels j'ai accès, j'ai :
"basic_ios::clear" (g++),
"iostream object has failbit set" (Sun CC/Rogue Wave),
"ios failure" (Sun CC/STL port), and
"ios_base::failbit set" (VC++/Dinkumware).
J'ai comme un petit soupçon qu'il voulait plus d'information que
ça.

--
James Kanze (GABI Software) email:
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


Avatar
Marc Boyer
Le 15-05-2007, James Kanze a écrit :
Parmi les quatre auxquels j'ai accès, j'ai :
"basic_ios::clear" (g++),
"iostream object has failbit set" (Sun CC/Rogue Wave),
"ios failure" (Sun CC/STL port), and
"ios_base::failbit set" (VC++/Dinkumware).
J'ai comme un petit soupçon qu'il voulait plus d'information que
ça.


Heu, oui...
Le strerror(ernno) est bien plus parlant quand même.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

Avatar
Marc Boyer
Le 15-05-2007, James Kanze a écrit :
On May 14, 1:32 pm, Marc Boyer
wrote:

je débute avec les fichiers, et je me demandais comment
on faisait pour avoir la cause de l'erreur.

Je fais un
ofstream f("toto.txt");
if (!f.is_open()){
cerr<<"Impossible d'ouvrir toto.txt "<<strerrno(errno)<<endl;
}

Mais est-ce bien la C++-attitude ?


Pourquoi pas ?


Je sais pas. Je demande. C'est la première fois depuis
longtemps que j'inclus un .h dans mon code C++.
Je me demandais s'il n'y avait pas une surcouche C++.

Formellement, la situation est exactement pareille qu'en C. La
fonction dit s'il a réussi ou non, mais la norme ne prévoit
aucune indication en ce qui concerne le pourquoi d'un échec.
Tout au plus permet-elle à l'implémentation de modifier errno,
sans pour autant l'exiger ni spécifier des valeurs qu'errno
pourrait éventuellement prendre.


Ca, je comprends bien: les systèmes de fichiers étants
variés, il seraient difficile de spécifier tous les messages
d'erreur. Mais dans la pratique, errno/strerror/perror
s'en sortent bien.

Dans la pratique, sur des plateformes Unix et semblable, et
filebuf::open et fopen vont se réposer sur la fonction Posix
open, et c'est elle qui positionne en fait errno en cas
d'erreur. En revanche, je n'ai malheureusement pas d'expérence
sur ce sujet sous Windows ; je ne saurais donc dire si c'est
aussi le cas là que errno soit positionné. (En renvanche, je
serais très étonné que filebuf::open et fopen se comportent de
manière différente, quelque soit la plateforme.)


Merci pour les renseignements,
Marc Boyer


--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)


Avatar
Marc Boyer
Le 15-05-2007, Michel Decima a écrit :
On May 14, 2:54 pm, Michael DOUBEZ wrote:

En utilisant open() qui est susceptible de lancer une exception à
condition de l'avoir activer avant:
ofstream f;

// Lancer une exception si "failbit" ou "badbit" est levé
f.exceptions (ios::failbit | ios::badbit);

try
{// Open will throw on error
f.open ("toto.txt");}

catch (exception &e)
{
cerr << "Impossible d'ouvrir toto.txt : " << e.what () << endl;
}


C'est un peu tordu d'utiliser des exceptions dans ce cas-ci,
non ?


Je trouve aussi. Et il faudrait penser a nettoyer les drapeaux
d'exception apres l'ouverture, si on veut garder un comportement
"classique" des flux, au moins en lecture.


Oui, j'avais encapsulé le tout dans une fonction try_open
qui refaisait un f.exceptions( ios::goodbit) après
l'ouverture.
Mais vu la pauvreté des messages d'erreur, je fais aussi
un
cerr<<strerror(errno)
dans le catch...

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



Avatar
Michel Decima
On May 14, 2:54 pm, Michael DOUBEZ wrote:

En utilisant open() qui est susceptible de lancer une exception à
condition de l'avoir activer avant:
ofstream f;

// Lancer une exception si "failbit" ou "badbit" est levé
f.exceptions (ios::failbit | ios::badbit);

try
{// Open will throw on error
f.open ("toto.txt");}

catch (exception &e)
{
cerr << "Impossible d'ouvrir toto.txt : " << e.what () << endl;
}


C'est un peu tordu d'utiliser des exceptions dans ce cas-ci,
non ?


Je trouve aussi. Et il faudrait penser a nettoyer les drapeaux
d'exception apres l'ouverture, si on veut garder un comportement
"classique" des flux, au moins en lecture. Le code suivant
se termine par une exception, meme si le fichier est present:

std::ifstream f;
f.exceptions( ios::failbit | ios::badbit );

try {
f.open( "toto.txt" );
std::string line;
while ( getline( f, line ) ) {
std::cout << line << "n";
}
}
catch ( std::exception& e ) {
std::cerr << "Exception: " << e.what() << std::endl;
}


Avatar
Alain Gaillard
En revanche, je n'ai malheureusement pas d'expérence
sur ce sujet sous Windows ; je ne saurais donc dire si c'est
aussi le cas là que errno soit positionné.


Sous Windows c'est forcément différent ;)
Au niveau du système, tu dois appeler l'API GetLastError pour savoir ce
qui s'est passé.
Mais pour le peu de fois où j'ai eu à m'en servir, avec un compilateur
Borland, le runtime fournissait bien une variable globale errno qu'il se
charge de remplir. Donc à priori on peut bien coder de la même façon
avec errno sous Windows et Unix.

--
Alain

Avatar
Michael DOUBEZ
On May 14, 2:54 pm, Michael DOUBEZ wrote:

En utilisant open() qui est susceptible de lancer une exception à
condition de l'avoir activer avant:
ofstream f;

// Lancer une exception si "failbit" ou "badbit" est levé
f.exceptions (ios::failbit | ios::badbit);

try
{// Open will throw on error
f.open ("toto.txt");}

catch (exception &e)
{
cerr << "Impossible d'ouvrir toto.txt : " << e.what () << endl;
}


C'est un peu tordu d'utiliser des exceptions dans ce cas-ci,
non ?


Je trouve aussi. Et il faudrait penser a nettoyer les drapeaux
d'exception apres l'ouverture, si on veut garder un comportement
"classique" des flux, au moins en lecture. Le code suivant
se termine par une exception, meme si le fichier est present:


Je suis d'accord que, vu l'inutilité des messages, l'activation de
l'exception est superflu.
C'est dommage que l'exception lancée par open() n'inclue pas un champ
errno (à défaut d'avoir un message plus informatif).

Peut être dans ce cas, refaire un filebuf qui lance une exception
personnalisé en utilisant les fonctions POSIX.

Michael



Avatar
James Kanze
On May 15, 10:57 am, Michael DOUBEZ wrote:
On May 14, 2:54 pm, Michael DOUBEZ wrote:

En utilisant open() qui est susceptible de lancer une exception à
condition de l'avoir activer avant:
ofstream f;

// Lancer une exception si "failbit" ou "badbit" est levé
f.exceptions (ios::failbit | ios::badbit);

try
{// Open will throw on error
f.open ("toto.txt");}

catch (exception &e)
{
cerr << "Impossible d'ouvrir toto.txt : " << e.what () << endl;
}


C'est un peu tordu d'utiliser des exceptions dans ce cas-ci,
non ?


Je trouve aussi. Et il faudrait penser a nettoyer les drapeaux
d'exception apres l'ouverture, si on veut garder un comportement
"classique" des flux, au moins en lecture. Le code suivant
se termine par une exception, meme si le fichier est present:


Je suis d'accord que, vu l'inutilité des messages, l'activation de
l'exception est superflu.
C'est dommage que l'exception lancée par open() n'inclue pas un champ
errno (à défaut d'avoir un message plus informatif).


C'est dommage que les iostream en général, et les fstream en
particulier, ne donne pas plus d'informations en ce qui concerne
la source d'une erreur. Dans certains cas, c'est même impossible
à savoir s'il y a eu une erreur de format sur la dernière
entrée.

Peut être dans ce cas, refaire un filebuf qui lance une exception
personnalisé en utilisant les fonctions POSIX.


Pourquoi toujours les exceptions ? Rien n'empêche filebuf
d'avoir des fonctions supplémentaires, dont une pour indiquer le
type de la dernière erreur vue.

--
James Kanze (GABI Software) email:
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