IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SL & STL C++ Discussion :

[std::ifstream] Lecture formatée lente


Sujet :

SL & STL C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut [std::ifstream] Lecture formatée lente
    Salut,

    Quelqu'un m'a demandé comment optimiser une lecture de fichier formatée qui était trop lente, et je ne savais pas vraiment comment faire.

    Je lui ai d'abord demandé s'il ne pouvait pas utiliser des bibliothèques déjà faites, mais il ne savait pas si son tuteur l'autorisait à le faire.

    Les fichiers qu'il doit lire sont des images au format texte, .ppm, qui se présente sous la forme suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    P3
    # commentaire... genre généré par Irfanview
    128 128
    255
    0 255 255 0 128 120 ...
    ...
    - La première ligne, c'est un nom de code.
    - La deuxième ligne, c'est un commentaire.
    - La 3e ligne : largeur et hauteur
    - La 4e ligne : la valeur max autorisée pour les entiers qui suivent
    - Le reste des lignes (le nombre d'entiers sur une ligne n'est pas constant) : les composantes RVB de chaque pixel.

    Il utilise std::ifstream pour lire, il alloue le vecteur de pixel à l'avance dès que la taille de l'image est connue, et il fait une double boucle pour lire les pixels du fichier.

    Le problème, c'est pour charger une image genre qui fait environ 4.5 Mo (ça fait environ 640x480 pixels), ça met 3 secondes sur son ordinateur environ, alors qu'Irfanview le lit quasi instantanément.

    C'est bien trop lent, il est censé analyser des images qui sortent d'une webcam à une fréquence assez soutenue genre 10 fois par sec.

    • Comment s'y prendre ? std::streambuf, c'est pas pour des choses formatées.
    • C'est pas mieux de charger le tout dans un std::string et d'utiliser un parseur ?

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Par défaut
    Si les performances sont importantes mieux vaut choisir un format d'image binaire (code P6 au lieu de P3 dans le ppm par exemple).

    Mais même dans ce cas, il faudra une machine très rapide pour traiter 10 images par seconde (~10Mo par seconde en lecture/écriture).

    En général, pour du temps réel, on ne passe pas par le disque, on traite tout directement en RAM.

  3. #3
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Bah, je serais bien passé au format binaire à sa place, mais c'est pas mon projet :/.

    C'est sûr c'est plus rapide, mais comment le logiciel Irfanview arrive-t-il à le charger en 2 ou 3 dixièmes de secondes ?

    (peut-être qu'en fait pour l'instant il travaille avec P3 pour tester les fonctionnalités, puis je pense pas que sa webcam créerait des fichiers au format texte).

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Ce que tu peux faire, c'est de passer par un buffer qui prend l'ensemble de l'image d'une seule traite...

    Ainsi, la gestion restante se fera directement au travers d'informations contenues dans la ram, et non plus au travers d'un acces disque

    Pour ce faire, tu peux te baser sur l'entrée de la faq qui en parle: http://c.developpez.com/faq/cpp/?pag...RS_full_buffer

    Je ne serais pas tres étonné que ce simple fait permettra déjà d'obtenir de bien meilleures performances, meme en considérant le temps nécessiare à la convertion des valeurs à lire, du simple fait que tout le fichier sera lu d'une seule traite, alors que sinon, il faille attendre, parfois, que le disque dur termine son tour afin de retrouver le secteur auquel il doit accéder
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 38
    Par défaut
    Un exemple qui indique comment fixer la taille du buffer:

    http://www.cplusplus.com/reference/i...pubsetbuf.html

    // set character buffer (pubsetbuf)
    #include <fstream>
    using namespace std;

    int main () {

    char mybuffer [512];
    fstream filestr;
    filestr.rdbuf()->pubsetbuf(mybuffer,512);

    // operations with file stream here.

    return 0;
    }

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Heu...

    En quoi l'entrée de la FAQ que je présente te chagrine-t-elle

    D'autant plus qu'il s'agit, non pas de fixer la taille du buffer du fichier, mais bel et bien de récupérer l'intégralité du fichier dans une structure qui nous permettra d'en récupérer les données par la suite...

    En gros, le code final serait sans doute du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    //ouverture du fichier
     
    std::ifstream fichier(nom.c_str());//ou nom est une std::string contenant
                                      //... le nom du fichier à ouvrir
    if(fichier)
    {
        std::stringstream buffer;
        buffer<<fichier.rdbuf();
        fichier.close();
        std::string str;
        buffer>>str;
        //la première ligne doit etre "P3"
        if(str!="P3") //c'est peut etre à adapter ;)
            throw std::runtime_error("format invalide");
        la deuxième ligne doit etre un commentaire
        std::getline(buffer,str);
        if(str[0]!='#')
            throw std::runtime_error("format invalide");
        int ligne;
        int colone;
        buffer>>ligne>>colone;
        //création du tableau à afficher (il s'agit en fait d'un tableau de char
        //dont les valeurs doivent etre récupérée
        char *final=new char[ligne*colone];
        //la dernière boucle
        for(int i=0;i< ligne*colone;i++) //si le compilo fait bien son travail, 
        // ce ne sera pas plus lent que d'avoir calculé un total=ligne*colone
        // au par avant
        {
            //ce qu'on lit, c'est un entier
            int lu;
            buffer>>lu;
            fini[i]=(char)lu;//permet de ne prendre que les 8 bits de l'entier qui
                             //nous intéresse
        }
        //on peut retourner le tableau final
        return fini;
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Repétition lecture formaté ifstream.
    Par Antares38 dans le forum SL & STL
    Réponses: 4
    Dernier message: 22/01/2010, 11h43
  2. [SL] std::ifstream vers FILE
    Par yan dans le forum SL & STL
    Réponses: 2
    Dernier message: 07/08/2007, 16h08
  3. [win2003 std]Apply Personnal settings LENT !
    Par ChristopheOce dans le forum Windows Serveur
    Réponses: 2
    Dernier message: 14/05/2007, 12h48
  4. Ifstream > Lecture d'un fichier > Format
    Par Zenol dans le forum SL & STL
    Réponses: 15
    Dernier message: 19/12/2005, 11h04
  5. Réponses: 4
    Dernier message: 04/11/2005, 09h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo