OVH Cloud OVH Cloud

Fichier temporaire ouvert en lecture / ecriture

12 réponses
Avatar
Vincent Lascaux
Bonjour,

J'utilise un fichier temporaire pour y écrire pas mal d'info, avant de le
relire pour les traiter. J'utilise un fstream pour cela, mais celà ne
fonctionne pas comme je l'esperais...
Pourquoi est ce que le code suivant s'entête à écrire "Has read 0 chars" ?

#include <fstream>
#include <iostream>

int main()
{
std::fstream file("temp.tmp", std::ios_base::in | std::ios_base::out |
std::ios_base::trunc | std::ios_base::binary);
std::string test = "Une chaine de caractères";

file.write(&test[0], test.size());
file.flush();
file.seekg(0);

char buffer[100];
int len = file.readsome(buffer, 100);
buffer[len] = 0;

std::cout << "Has read " << len << " chars: " << buffer << std::endl;
}

La seule solution que j'ai trouvé consiste à fermer et à réouvrir le
fichier... Je ne trouve vraiment pas ca très propre. Est ce un bug de Visual
Studio, ou est ce le comportement prévu par la norme ?

Merci

--
Vincent

10 réponses

1 2
Avatar
Franck Branjonneau
"Vincent Lascaux" écrivait:

Pourquoi est ce que le code suivant s'entête à écrire "Has read 0 chars" ?


Sous réserves, je ne suis pas familier de cette partie de la bibliothèque.

#include <fstream>
#include <iostream>

int main()
{
std::fstream file("temp.tmp", std::ios_base::in | std::ios_base::out |
std::ios_base::trunc | std::ios_base::binary);
std::string test = "Une chaine de caractères";

file.write(&test[0], test.size());
file.flush();
file.seekg(0);

char buffer[100];
int len = file.readsome(buffer, 100);
buffer[len] = 0;

std::cout << "Has read " << len << " chars: " << buffer << std::endl;
}


D'abord, tu devrais tester tes opérations d'E/S. D'un manière générale
les fonctions sur les flux se contentent de ne rien faire lorsque que
le flux cible n'est pas "good".

Ensuite, la fonction basic_istream<>::readsome lis les caractères
disponibles dans le buffer du flux; si il n'y en pas, il y en a 0 ;-).
Je penses que les fonctions que tu cherches sont basic_istream<>::get
et basic_istream<>::gcount.
--
Franck Branjonneau

Avatar
James Kanze
Vincent Lascaux wrote:

J'utilise un fichier temporaire pour y écrire pas mal d'info,
avant de le relire pour les traiter. J'utilise un fstream pour
cela, mais celà ne fonctionne pas comme je l'esperais...


Pourquoi est ce que le code suivant s'entête à écrire "Has
read 0 chars" ?


#include <fstream>
#include <iostream>


int main()
{
std::fstream file("temp.tmp", std::ios_base::in | std::ios_base::out |
std::ios_base::trunc | std::ios_base::binary);
std::string test = "Une chaine de caractères";


file.write(&test[0], test.size());


Et ça doit donner quoi, à ton avis ? Je ne crois pas que ce soit
la source de ton problème, mais il y a un gros comportement
indéfini ici.

file.flush();
file.seekg(0);


char buffer[100];
int len = file.readsome(buffer, 100);


Et là, tu lis selon ce que veut l'implémentation. Typiquement,
je crois, tu va lire les caractères actuellement disponible dans
le buffer, et rien de plus, et typiquement, après un seek, il
n'y en aura pas.

buffer[len] = 0;


std::cout << "Has read " << len << " chars: " << buffer << std::endl;
}


La seule solution que j'ai trouvé consiste à fermer et à
réouvrir le fichier... Je ne trouve vraiment pas ca très
propre. Est ce un bug de Visual Studio, ou est ce le
comportement prévu par la norme ?


La norme ne prévient rien. L'implémentation est libre à faire ce
qu'il veut. Dans ce cas-ci, c'est même difficile à savoir ce qui
a été l'intention. (Malheureusement, c'est souvent le cas quand
il s'agit des fonctions que la norme a ajouté aux iostream
classique.)

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Avatar
Vincent Lascaux
D'abord, tu devrais tester tes opérations d'E/S. D'un manière générale
les fonctions sur les flux se contentent de ne rien faire lorsque que
le flux cible n'est pas "good".


C'est juste... Pour être de mauvaise fois, je dirais que je le fais
*évidemment* dans mes programmes, mais que pour un soucis de simplicité je
l'avais pas fait dans le petit exemple (pour en alleger la lecture) 0:)

Ensuite, la fonction basic_istream<>::readsome lis les caractères
disponibles dans le buffer du flux; si il n'y en pas, il y en a 0 ;-).


Oui, j'avais compris ca... mais c'est bien le problème : il retourne 0, mais
là il y en a des caracteres (je viens juste d'ecrire une chaine dans le
fichier).
Moi j'attends que le programme m'écrire Has read 24 chars: Une chaine de
caractères

Je penses que les fonctions que tu cherches sont basic_istream<>::get
et basic_istream<>::gcount


Mes données sont binaires. Je ne veux surtout pas m'arrêter à chaque fois
que je rencontre un 'n'...

--
Vincent

Avatar
Vincent Lascaux
std::string test = "Une chaine de caractères";

file.write(&test[0], test.size());


Et ça doit donner quoi, à ton avis ? Je ne crois pas que ce soit
la source de ton problème, mais il y a un gros comportement
indéfini ici.


Ah ? zut...
Quelle en est la raison ? Les caracteres d'une string ne sont pas
nécessairement les uns après les autres ? C'est plut un comportement
indéfini si je fais

file.write(test.data(), test.size());

?

Si les caracteres de la string ne sont pas nécessairement les uns après les
autres, quelle est la durée de vie de la mémoire pointée par test.data() ?

Et là, tu lis selon ce que veut l'implémentation. Typiquement,
je crois, tu va lire les caractères actuellement disponible dans
le buffer, et rien de plus, et typiquement, après un seek, il
n'y en aura pas.


D'accord... Après test, c'est effectivement mieux avec get et gcount...

Merci

--
Vincent


Avatar
kanze
Vincent Lascaux wrote:
std::string test = "Une chaine de caractères";

file.write(&test[0], test.size());


Et ça doit donner quoi, à ton avis ? Je ne crois pas que ce
soit la source de ton problème, mais il y a un gros
comportement indéfini ici.


Ah ? zut...

Quelle en est la raison ? Les caracteres d'une string ne sont
pas nécessairement les uns après les autres ?


Il n'y a aucune exigence de contiguïté dans la représentation
interne d'une chaîne. L'adresse du premier caractère n'est que
l'adresse du premier caractère ; on ne peut pas en ajouter un
pour obtenir l'adresse du deuxième caractère.

C'est plut un comportement indéfini si je fais

file.write(test.data(), test.size());

?


Pas du tout. L'expression test.data() existe exactement pour ce
genre d'utilisation. L'adresse qu'il renvoie doit désigner un
tableau contigu des caractères. (Mais l'adresse qu'il renvoie
n'est pas forcément la même que &test[0].)

Si les caracteres de la string ne sont pas nécessairement les
uns après les autres, quelle est la durée de vie de la mémoire
pointée par test.data() ?


Jusqu'à l'appel de la prochaine fonction non-const.

Et là, tu lis selon ce que veut l'implémentation.
Typiquement, je crois, tu va lire les caractères
actuellement disponible dans le buffer, et rien de plus, et
typiquement, après un seek, il n'y en aura pas.


D'accord... Après test, c'est effectivement mieux avec get et
gcount...


Une autre possibilité serait file.rdbuf()->sgetn().

--
James Kanze GABI Software
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
Franck Branjonneau
écrivait:

L'expression test.data() existe exactement pour ce genre
d'utilisation. L'adresse qu'il renvoie doit désigner un tableau
contigu des caractères. (Mais l'adresse qu'il renvoie n'est pas
forcément la même que &test[0].)


Vraiment ?

21.3.4/1.

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);

Returns: If pos < size(), returns data()[pos]. [...]
--
Franck Branjonneau

Avatar
Vincent Lascaux
21.3.4/1.

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);

Returns: If pos < size(), returns data()[pos]. [...]


Il me semble que ca n'empêche pas : data()[pos] vaut le "pos-ième" caractère
de la chaine. Maintenant, la chaîne peut l'obtenir d'une autre façon qu'elle
juge plus performante.
Ce qui m'inquiète plutot c'est que si la chaîne ne stoque pas les données
linéairement (ie comme dans data), lors de l'appel à data, j'utilise deux
fois plus de mémoire (puisque data doit bien être créé en mémoire) et ce
jusqu'à ce que je fasse un appel à une fonction non const... ca m'embête un
peu ca (en fait ca m'embête tellement que j'ai décidé d'utiliser un
vector<char> pour mon cas... ca marche très bien)

--
Vincent

Avatar
Loïc Joly
21.3.4/1.

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);

Returns: If pos < size(), returns data()[pos]. [...]



Il me semble que ca n'empêche pas : data()[pos] vaut le "pos-ième" caractère
de la chaine. Maintenant, la chaîne peut l'obtenir d'une autre façon qu'elle
juge plus performante.


Sauf qu'on parle ici d'un retour par référence, et non par valeur...

--
Loïc


Avatar
Gabriel Dos Reis
writes:

[...]

| > C'est plut un comportement indéfini si je fais
|
| > file.write(test.data(), test.size());
|
| > ?
|
| Pas du tout. L'expression test.data() existe exactement pour ce
| genre d'utilisation. L'adresse qu'il renvoie doit désigner un
| tableau contigu des caractères. (Mais l'adresse qu'il renvoie
| n'est pas forcément la même que &test[0].)

J'ai du mal à trouver d'ou vient cette garantie -- il faut dire qu'il
est tard et je suis fatigué. Aussi, j'apprecierais une référence à la
norme où je peux trouver cette garantie.

-- Gaby
Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

writes:

[...]

| > C'est plut un comportement indéfini si je fais
|
| > file.write(test.data(), test.size());
|
| > ?
|
| Pas du tout. L'expression test.data() existe exactement pour ce
| genre d'utilisation. L'adresse qu'il renvoie doit désigner un
| tableau contigu des caractères. (Mais l'adresse qu'il renvoie
| n'est pas forcément la même que &test[0].)

J'ai du mal à trouver d'ou vient cette garantie -- il faut dire qu'il
est tard et je suis fatigué. Aussi, j'apprecierais une référence à la
norme où je peux trouver cette garantie.


C'est a l'endroit le plus evident. Tu dois etre effectivement bien
fatigue.

21.3.6/3:

If size() is nonzero, the member [data()] returns a pointer to the
initial element of an array whose first size() elements equal the
corresponding elements of the string constrolled by *this. If size()
is zero, the member returns a non-null pointer that is copyable and
can have zero added to it.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

1 2