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

C++ Discussion :

Rechercher des doublons dans un fichier de type csv


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut Une application qui fige lors d'un évènement sur la frame.
    Bonjour tout le monde,

    Je vais essayer de faire simple.
    Je développe une application sous wx-Devcpp.
    Objectif: rechercher des doublons de lignes dans un fichier de type csv.

    Voilà à quoi ressemble le fichier de données:

    NOM;PRENOM;N°SECU;n°RUE;nom RUE;VILLE
    Someone;Jonathan;123456789012345;13;rue de l'étang;Ici
    Somebody;Sébastien;123456789012344;1;avenue les bains;Là bas
    Someone;Jonathan;123456789012345;13;rue de l'étang;Ici
    Dans le cas actuel, le fichier en question est ouvert, lu et stocké intégralement dans un buffer alloué dynamiquement.
    Ensuite, pour l'instant, l'application parcourt linéairement le buffer caractère par caractère à la recherche du champ le plus long.

    La taille du fichier à analyser semble être un obstacle:

    Avec un petit fichier de test, tout se passe bien.
    A partir d'environ 1Mo, l'application se met à fortement ralentir, et si par malheur la fenêtre perd le focus ou est déplacée, celle ci fige et ne répond
    plus.
    L'application fige également au bout d'un certain temps.


    Pensez vous qu'il soit bien de stocker tout un fichier en mémoire pour travailler avec le contenu ?
    (celui-ci pourra atteindre au maximum 50Mo) ?

    Merci d'avance pour votre aide.

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    50 Mo oula t'es fou???
    non je déconne c'est vraiment pas beaucoup 50 Mo...
    Si tu peut expliquer un peu plus ton algo et voir même un peu de code.
    On pourras surement t'aider

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    La bonne question est surtout de savoir ce que tu veux faire avec les doublons trouvés...

    Si, comme on est tenté de le croire, le but est de supprimer les valeurs en double, l'une des solutions les plus simple pourrait, tout simplement,
    1. de créer une structure permettant de stocker les informations
    2. prévoir l'opérateur < pour cette structure (nécessaire pour le tri des set et des map)
    3. lire les éléments un à un
    4. placer le éléments dans un set - voire, pourquoi pas, dans une map - parce que cela assure l'unicité des élément que le conteneur contient
    5. réécrire le contenu du set ou de la map après lecture du fichier complet


    Si le but est différent, d'autres solutions peuvent être envisagées
    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

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut
    L'objectif est juste de signaler tout ou partie des lignes redondantes.
    Je n'envisage pas de les supprimer, mais juste d'afficher un message avec le numéro des lignes doublonnées.


    Voici quelques extraits de code:
    • fonction pour ouvrir le fichier et stocker le contenu dans le buffer alloué dynamiquement (appelée suite à l'évènement OK de la boite de dialogue d'ouverture de fichiers)


    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    void load_datafile()
    {
        FILE *fd;
        file_fullname = wxFileSelector("Choose a file to open");
     
        long sizeofile=0;  // datafile length
        long result;  // fucking variable to count the number of effective readed caracters in datafile!
     
     
        // if the openfile Dialog returned something true
        if ( !file_fullname.empty() )
        {
            // get full pathfile in char*
            const char *pFileName = file_fullname.mb_str();
            // and then try to open the file in READ ONLY and get a valid descriptor!
            if((fd = fopen(pFileName,"rb")) != NULL)
            {
                /**** get file size *****/
                fseek( fd, 0L, SEEK_END );
                long endPos = ftell( fd );
                sizeofile = endPos;
                wxLogStatus("longueur fichier de données = %ld octets", sizeofile);
                rewind(fd);
     
                /**** get file content *****/
                // allocate dynamic memory to get this...
                buffer = (char*) malloc( sizeof(char) * sizeofile);
     
                // copy the file into the buffer:
                result = fread (buffer,1,sizeofile,fd);
                if (result != sizeofile)
                {
                    wxLogMessage("Erreur de lecture dans le fichier!");
                    fflush(stdin);
                    getchar();
                    exit(-1);
                }
     
                loaded=true;    // fichier chargé...
                fclose(fd);
            }
            else    // should happends if open fails
            {
                loaded=false;    // fichier non chargé...
                wxLogMessage("Impossible d'ouvrir le fichier: %s",pFileName);
                // then exit from "Mnuopen1007Click" ...
            }
     
     
        }
        else
        {
            wxLogMessage("Pas de fichier ouvert!");
        }
    }


    • Voici la fonction qui détermine la longueur du plus grand champ dans le fichier csv (appelée lors d'un clic sur le bouton "analyser")



    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
    40
    41
    42
    43
    44
    45
    46
    int identify_fields()
    {
     
        int i=0;
     
        int field_len;      // tmp field length
        int longest_field;  // size of the longest field (to determine how much allocate for a field) --> of course there is no optimisation of memory!!!
     
     
        // just a security (file must have been loaded, if not leave the function)
        if (loaded!=true)
            return -1;
     
     
     
        /*** Get the longest field in the file (for static size fields length allocation) ***/
     
        int aze=0;
     
        field_len=0;
        longest_field=0;
        for (i=0;i<(int)strlen(buffer);i++)
        {
                    // if data concern any of field content...
            if (buffer[i]!=';' && buffer[i]!='\n')
                field_len++;
            else    // otherwise compare this calculated value with the longest_field one, and if greater, update...
            {
                if (field_len > longest_field)
                    longest_field = field_len;
                field_len=0;    // of course, reset the field_len count!
            }
     
            aze++;
            if (aze>9)
            {
                wxLogStatus("Lu %d / %d", i, (int)strlen(buffer) );
                aze=0;
            }
     
        }
        wxLogMessage("champ le plus grand vaut %d caracteres", longest_field);
     
     
        return 0;
    }

    Ces 2 fonctions sont déclarées dans le même fichier (csv-Parser.cpp).
    La variable buffer est déclarée en global.

    Pour l'algo, actuellement il peut ressembler à ça:

    SI un fichier est ouvert
    déterminer sa taille
    allouer dynamiquement de la mémoire pour contenir le fichier
    FIN SI

    SI click sur Bouton "Analyser"
    TANT QUE (pas fin de fichier)
    {
    si (caratère lu <> ';' et caractère lu <> '\n')
    incrémenter taille temporaire du champ
    sinon
    {
    si (taille temporaire > taille max)
    {
    taille max = taille temporaire
    }
    taille temporaire = 0
    }

    afficher périodiquement dans la barre d'état l'octet en cours de lecture
    }
    FIN TANT QUE

    enfin afficher la taille du champ le plus long trouvé
    FIN SI

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut Application développée en wx-Devcpp qui fige
    Bonjour, me revoilà!
    J'ai résolu une partie de mon problème en faisant une allocation dynamique de mémoire en utilisant new et delete plutôt que malloc et free.

    Le positif: l'application réussit maintenant à balayer tout le fichier sans se bloquer.

    Le négatif: Lorsque celle ci est en cours et parcourt le fichier, ne surtout pas cliquer sur sa fenêtre, tenter de la déplacer ou même faire autre chose comme aller par exemple lire ses mails: celle ci fige et y apparait en haut à gauche "ne répond pas".

    Vous avez une idée?

    Pour info, c'est à l'éxecution de cette boucle qui peut durer très longtemps (dépend de la taille du fichier) que survient le problème.

    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
     
        field_len=0;
        longest_field=0;
        for (i=0;i<(int)strlen(buffer);i++)
        {
            // si la donnée n'est pas un délimiteur
            if (buffer[i]!=';' && buffer[i]!='\n')
                field_len++;
            else    // alors fin du champ n°X
            {
                if (field_len > longest_field)
                    longest_field = field_len;
                field_len=0;
            }
     
            aze++;
            if (aze>9)
            {
                wxLogStatus("Lu %d / %d", i, (int)strlen(buffer) );
                aze=0;
            }
     
        }
        wxLogMessage("champ le plus grand vaut %d caracteres", longest_field);
    Merci à vous koala01 et Mongaulois pour vos réponses.
    (Dès que ce bug sera résolu, je passerai à l'étape stockage des données)

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut
    Re bonjour,

    J'ai trouvé la solution au problème

    Il faut gérer les évènements, ou plutôt donner un peu de temps au système pour qu'il puisse le faire!

    Pour celà, l'appel de la fonction membre Yield(); est indispensable avant d'afficher quelque chose dans le status control.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    aze++;
    if (aze>9)
    {
          // use of Yield member to avoid freezes when something is displayed...
          pointeur->Yield(false);
          wxLogStatus("Lu %d / %d", i, (int)strlen(buffer) );
          aze=0;
    }

    Cette page m'a beaucoup aidé:
    http://docs.wxwidgets.org/stable/wx_...s.html#wxyield

    Il ne faut juste pas oublier d'initialiser le pointeur de classe wxApp avant l'appel de Yield() via:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    wxApp *pointeur = new wxApp;

    Bon codage!

  7. #7
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 354
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 354
    Points : 1 419
    Points
    1 419
    Par défaut
    pour moi il faudrait mettre le fichier dans un gros char*
    puis n'utiliser que des pointeurs sur cette zone memoire (des string a la C)
    et utiliser des map<char*,char*> avec une fonction de comparaison pour les char*

    donc tu n'utiliseras que la memoire necessaire pour le fichier et pas de copie de string a gogo.

    ps: je l'ai deja fait et ca marche vraiment super (j'avais aussi implementé la methode basique, je lis le fichier et je cree ma structure de donnée avec std::string, pas performante du tout)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 04/11/2008, 21h46
  2. Rechercher des données dans un fichier txt
    Par joboy84 dans le forum Langage
    Réponses: 5
    Dernier message: 11/06/2008, 15h00
  3. recherche des doublons dans une hash
    Par Jasmine80 dans le forum Langage
    Réponses: 4
    Dernier message: 29/01/2007, 11h51
  4. Prbleme de liaison avec des doublons dans le fichier lié.
    Par krak70 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 16/10/2005, 11h03
  5. recherche de doublons dans un fichier texte
    Par portu dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 07/10/2003, 14h13

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