OVH Cloud OVH Cloud

lire un fichier dans une string

9 réponses
Avatar
David Bellot
Bonjour,

mon probleme est simple mais aucune solution apres des heures de Google.
J'ai un gros fichier (129Go) que je ne peux pas couper en morceaux mais
que je lis par partie avec un

ifstream f("mon_fichier");
f.seekg(nouvelle_position);
f.read(buffer, taille);

ensuite je met tout ca dans une string

string s = buffer;

et ensuite j'utilise cette string dans une librairie (Boost en l'occurence).

Mais voila, ca me coute un constructeur de copie a chaque que je passe
de buffer a la string s et vu la taille de mon fichier, c'est tres cher.

Je voudrais donc remplir ma string directement depuis mon fichier sans
passer par un buffer intermediaire.

Apres avoir regarder avec istream_iterator, je me suis rendu compte
qu'on ne peut pas aller se positionner ou l'on veut dans le fichier avec
ce type d'iterateur.

Quelle est la solution a ce probleme ?
Merci pour votre aide.

David

9 réponses

Avatar
loufoque

Quelle est la solution a ce probleme ?


En voici une non standard

std::string s(taille);
f.read(&s[0], taille);

Avatar
Sylvain
David Bellot wrote on 29/09/2006 00:39:

J'ai un gros fichier (129Go) que je ne peux pas couper en morceaux mais
que je lis par partie avec un


plus de 128 Go de RAM, belle machine !

Sylvain.

Avatar
Loïc Joly
Bonjour,

mon probleme est simple mais aucune solution apres des heures de Google.
J'ai un gros fichier (129Go) que je ne peux pas couper en morceaux mais
que je lis par partie avec un


D'après tout ce que j'ai vu, quand on veut chaque poil de perf pour le
lecture de très gros fichiers, il faut hélàs laisser tomber les
fonctions standard et utiliser des api spécifiques à l'OS.

--
Loïc

Avatar
Fabien LE LEZ
On Fri, 29 Sep 2006 03:38:16 +0200, Loïc Joly
:

D'après tout ce que j'ai vu, quand on veut chaque poil de perf pour le
lecture de très gros fichiers, il faut hélàs laisser tomber les
fonctions standard et utiliser des api spécifiques à l'OS.


J'ai eu de gros soucis de performances avec les iostream, par contre,
les FILE* donnent plutôt des performances décentes, au moins sous
Windows.

M'enfin bon, sur le principe, je suis plutôt d'accord avec toi.

Avatar
kanze
loufoque wrote:

Quelle est la solution a ce probleme ?


En voici une non standard

std::string s(taille);
f.read(&s[0], taille);


Qui n'est actuellement pas garanti de marcher. Ou au moins, ce
n'est pas clair s'il est garanti ou non. Mais qui marche
actuellement avec toutes les implémentations, et qui serait
probablement garanti dans la prochaine version de la norme.

En fait, quelque chose du genre :

s.reserve( taille ) ;
char c ;
while ( taille > 0 && f.get( c ) ) {
s.push_back( c ) ;
}

ne doit pas être beaucoup moins rapide. (Ici, on a un test de
plus chaque fois dans la boucle, dans ta version, on initialise
toute la longueur avant de le lire.)

--
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
kanze
Loïc Joly wrote:
Bonjour,

mon probleme est simple mais aucune solution apres des
heures de Google. J'ai un gros fichier (129Go) que je ne
peux pas couper en morceaux mais que je lis par partie avec
un


D'après tout ce que j'ai vu, quand on veut chaque poil de perf
pour le lecture de très gros fichiers, il faut hélàs laisser
tomber les fonctions standard et utiliser des api spécifiques
à l'OS.


Il n'a pas parlé de chaque poil de perf, mais simplement
d'éliminer une copie (avec allocation, etc.) de trop.

--
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
kanze
David Bellot wrote:

mon probleme est simple mais aucune solution apres des heures
de Google. J'ai un gros fichier (129Go) que je ne peux pas
couper en morceaux mais que je lis par partie avec un

ifstream f("mon_fichier");
f.seekg(nouvelle_position);
f.read(buffer, taille);


D'où vient la nouvelle_position ? Si ce n'est pas le résultat
d'un f.tellg(), tu as un comportement indéfini ici. Si tu fais
des positionnements aléatoires dans le fichier, je te conseilles
fort de l'ouvrir en mode binaire, et de t'assurer qu'il soit
imbué du locale "C".

ensuite je met tout ca dans une string

string s = buffer;

et ensuite j'utilise cette string dans une librairie (Boost en
l'occurence).

Mais voila, ca me coute un constructeur de copie a chaque que
je passe de buffer a la string s et vu la taille de mon
fichier, c'est tres cher.


Si tu utilises constamment la même variable, et que tu as fait
un reserve adéquat avant de commencer, ça doit déjà aller mieux.

Je voudrais donc remplir ma string directement depuis mon
fichier sans passer par un buffer intermediaire.


C'est quasi impossible. ifstream a un buffer interne, l'API sur
laquelle il se base probablement aussi, et l'OS aussi. Tu as
déjà pas mal de buffers intermediaire, que tu le veuilles ou
non.

Ce qui est forte possible, en revanche, si chaque morceau que tu
lis est petit (rélativement), et donc que tu en lis beaucoup,
c'est que les allocations te bouffent un temps fou. La solution
là, pas nécessairement élégante, mais faisable quand même, c'est
de ne pas construire une chaîne nouvelle à chaque fois, mais
d'utiliser la même variable. En d'en avoir fait une reserve
adéquate au début.

Apres avoir regarder avec istream_iterator, je me suis rendu
compte qu'on ne peut pas aller se positionner ou l'on veut
dans le fichier avec ce type d'iterateur.


Avec l'itérateur, non. Mais tu peux positioner, puis créer
l'itérateur, et il lirait depuis la position où on se trouve.
Il ne doit pas être trop difficile non plus de wrapper
l'istream_iterator de façon à ce qu'il renvoie fin au bout d'n
fois (ou fin de fichier), ce qui permettrait quelque chose du
genre :

string s( iter( f ), iter( taille ) ) ;

(Je jetterais un coup d'oeil sur les adaptateurs et les façades
d'itérateur chez Boost. Il est probable que leur utilisation
puisse te faciliter pas mal la vie si tu prends ce chemin.)
Seulement, tu aurais encore les allocations, probablement même
plus, parce que std::string ne peut pas connaître la taille
finale avant de commencer. En revanche :

s.assign( iter( f ), iter( taille ) ) ;

ne doit pas être trop cher.

--
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
loufoque
loufoque wrote:

Quelle est la solution a ce probleme ?


En voici une non standard

std::string s(taille);
f.read(&s[0], taille);


Qui n'est actuellement pas garanti de marcher.


Oui, c'est ce que je voulais dire par "non standard".
À part ça il y a une erreur avec le constructeur de std::string, il faut
passer par reserve effectivement.



Avatar
Jean-Marc Bourguet
loufoque writes:

loufoque wrote:

Quelle est la solution a ce probleme ?


En voici une non standard

std::string s(taille);
f.read(&s[0], taille);
Qui n'est actuellement pas garanti de marcher.



Oui, c'est ce que je voulais dire par "non standard".
À part ça il y a une erreur avec le constructeur de std::string, il faut
passer par reserve effectivement.


Une alternative qui est garantie de marcher mais qui ne produit pas une
std::string, c'est d'utiliser un std::vector de la même façon.

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