Chercher une chaine dans un fichier (c++)

Fermé
youcef - 3 déc. 2009 à 19:49
 youcef - 4 déc. 2009 à 10:28
Bonjour,
j'ai coder cette fonction pour chercher une chaine (mot) dans un fichier (dir), elle marche tres bien pour les petits fichier ,mais pour les fichier de masse &éé"é"('"'-"'è('ç__àç-à_ç_ç)........

je cherche une solution pour ne pas charger tout le fichier en memoire
ou tout simplement une fonction qui marche a tout les coups
merci d'avance.

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <windows.h>

bool echercheDansUnFichier(char *dir,char *mot)
{
    FILE* file=NULL;
    long taille=0,i;

    if(
    !strstr(dir,".txt")&&
    !strstr(dir,".ini")&&
    !strstr(dir,".rtf")&&
    !strstr(dir,".doc")&&
    !strstr(dir,".ppt")&&
    !strstr(dir,".pdf")&&
    !strstr(dir,".htm")&&
    !strstr(dir,".xls")) return false;

    //printf("ouvrture de fichier \"%s\".\n",dir);

    file=fopen(dir,"r");
    if(file!=NULL)
    {
        fseek(file,0,SEEK_END);
        taille=ftell(file);
        rewind(file);
        char buf[taille+1];
        for(i=0;i<taille;i++)
        {
            buf[i]=tolower(fgetc(file));
        }
        fclose(file);
        buf[i]='\0';
        if(strstr(buf,mot)!=NULL)
        return true;
        else
        return false;
    }
    else
    {
    fprintf(stdout,"impossible d'ouvrir le fichier \"%s\".\n",dir);
    return false;
    }

}
A voir également:

7 réponses

Pacorabanix Messages postés 3248 Date d'inscription jeudi 23 août 2007 Statut Membre Dernière intervention 19 mai 2013 661
3 déc. 2009 à 20:33
Algorithme d'une solution : parcourir le fichier caractère par caractère jusqu'à ce que tu trouves le premier caractère recherché.

EX : si tu cherche le mot "chien", tu cherche caractère par caractère jusqu'à trouver "c".

Une fois le premier caractère trouvé, tu lis le fichier à cet endroit de la longueur qu'il faut (dans notre exemple, lire 5 caractères) et vérifier que c'est le mot que tu cherches.

Si ce n'est pas le cas, il faut reprendre la boucle principal, et donc rechercher le prochain 'c' dans notre exemple.

Ainsi, tu ne mets jamais qu'un seul caractère en mémoire, ou au pire une chaine de la taille de ce que tu cherches.

Ceci dit cette méthode n'est pas très efficace au niveau des ressources : on ne charge pas tout le fichier en mémoire, c'est vrai, mais elle va causer de très nombreux accès disques ce qui sera plutôt lent.

Avec les ordinateurs d'aujourd'hui, il y a peu de risque de se trouver en manque de mémoire, sauf si par exemple tu charges qqchose comme une vidéo.

Si vraiment tu risques de te retrouver en manque de mémoire, tu peux aussi faire un compromis : Tu te fixes une taille limite de mémoire à utiliser (disons 10 Mo par exemple), et si le fichier fait plus que 10Mo, tu ne lis que les 10 M premiers caractères (10 * 2^20 premiers caractères si ce sont en fait des Mio, comme habituellement). Ensuite tu appliques ta méthode sur ce morceau. Si ce n'est pas trouvé, tu recommences avec le reste du fichier, ou les 10 prochaine Mo du fichier s'il fait plus que 20 Mo, etc....

Attention ! Il y a le cas où ce que tu cherches peut être "coupé" entre les deux morceaux découpés. Ex : à la fin des 10 Mo il y a "chi" et au début des 10 prochains il y a "en"... à améliorer à ce niveau sinon risque de bug difficile à déceler : chaine pas trouvée alors qu'elle y est.
1
merci pour vos réponses.
la cause du SIGSEV était l'allocation de beaucoup de char l'algorithme de Pacorabanix a résolu ce problème(merci Pacorabanix)(j'ai traité le cas ou ton chien est coincer entre 2 morceaux LOL).
pour les caractères spéciaux j'ai coder ma propre strstr() c'est strstr2() qui ne s'appuie sur le (n) pour connaître la fin du buffer.
voici le nouveau code ,normalement il marche bien (si vous voyer un bug prévenez moi):
bool strstr2(const char* buf,const int n,const char* mot)
{
    int i=0,j;
    int len=strlen(mot);
    while(i<n)
    {
        j=0;
        while(buf[i+j]==mot[j]&&j<len)
        {
            j++;
        }

        if(j==len)
        {
            return true;
        }
        i++;
    }
    return false;
}

bool rechercheDansUnFichier(const char *dir,const char *mot)
{
    FILE* file=NULL;
    long taille=0,n=0,i,tailleMot=strlen(mot);
    char buf[1024*1024];


    file=fopen(dir,"r");

    if(file!=NULL)
    {
        fseek(file,0,SEEK_END);
        taille=ftell(file);
        rewind(file);
        while(0<taille)
        {
            n=1024*1024;
            if(n>taille)n=taille;
            taille-=1024*1024-tailleMot;
            for(i=0;i<n;i++)
            {
                buf[i]=tolower(fgetc(file));
            }

            if(strstr2(buf,n-tailleMot,mot))
            {
                return true;
            }
            fseek(file,-tailleMot,SEEK_CUR);
        }
        fclose(file);
        return false;
    }
    else
    {
    fprintf(stdout,"impossible d'ouvrir le fichier \"%s\".\n",dir);
    return false;
    }

}
1
[edit]
Bonjour,
j'ai coder cette fonction pour chercher une chaine (mot) dans un fichier (dir), elle marche tres bien pour les petits fichier ,mais pour les fichier de masse &éé"é"('"'-"'è('ç__àç-à_ç_ç)........

je cherche une solution pour ne pas charger tout le fichier en memoire
ou tout simplement une fonction qui marche a tout les coups
merci d'avance.

il y'a aussi ce signal SIGSEGV (c'est lui le vrai gros probleme) quand la fonction chercher a pour entré un executable ou une image (un fichier qui contiens des caractaires speciaux je crois)

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <windows.h>

bool cechercheDansUnFichier(char *dir,char *mot)
{
    FILE* file=NULL;
    long taille=0,i;

    if(
    !strstr(dir,".txt")&&
    !strstr(dir,".ini")&&
    !strstr(dir,".rtf")&&
    !strstr(dir,".doc")&&
    !strstr(dir,".ppt")&&
    !strstr(dir,".pdf")&&
    !strstr(dir,".htm")&&
    !strstr(dir,".xls")) return false;

    //printf("ouvrture de fichier \"%s\".\n",dir);

    file=fopen(dir,"r");
    if(file!=NULL)
    {
        fseek(file,0,SEEK_END);
        taille=ftell(file);
        rewind(file);
        char buf[taille+1];
        for(i=0;i<taille;i++)
        {
            buf[i]=tolower(fgetc(file));
        }
        fclose(file);
        buf[i]='\0';
        if(strstr(buf,mot)!=NULL)
        return true;
        else
        return false;
    }
    else
    {
    fprintf(stdout,"impossible d'ouvrir le fichier \"%s\".\n",dir);
    return false;
    }

}
0
grou29 Messages postés 39 Date d'inscription mardi 27 octobre 2009 Statut Membre Dernière intervention 19 mai 2010 9
3 déc. 2009 à 23:36
ceci devrait marcher (j'ai pas de compilo sur ma machine)

Le principe. on lit un caractere dans le fichier et on compare au premier caracter du mot.
si c'est pas bon on lit le suivant etc.
si c'est le bon, on passe au deuxième caractere du mot


taille=ftell(file);
int nbchar = strlen(mot);
int idxmot=0;
int idxfile=0;
long filepos;
bool trouve=false;

while ((trouve ==false) &&
(idxfile<taille))
{
char c= tolower(fgetc(file));
idxfile++;

if (c== mot[idx])
{
// une lettre de trouve, suivante
if (idx==0)
{
//1er lettre, on sauve la position dans le fichier au cas ou
filepos = ftell(file);
}
idx++;
if (idx==nbchar)
{
// toute les lettres ont été trouvées, c'est fini
trouve=true;
} else {
// pas bonne lettre, on recommence la ou on a sauvé la position (apres le 1er caractere bon)
fseek(file,filepos,SEEK_SET);
idxfile-= ftell(file);
idx=0;
}
}
if (trouve == true)
{
...
}
fclose(file);


-
Grou29
http://lienssanslien.free.fr
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
grou29 Messages postés 39 Date d'inscription mardi 27 octobre 2009 Statut Membre Dernière intervention 19 mai 2010 9
3 déc. 2009 à 23:53
Le temps que j'écrive mon code, Pacorabanix a eu la même idée :)

Pour ton SIGSEV, essaye de mettre un b sur ton fopen:
fopen(dir,"rb");

par défaut le fichier est ouvert en mode texte et certain caractères peuvent être interprétés comme une fin de fichier prématuré.

Sinon, si tu cherche le top du top , tu peux utiliser une projection mémoire (voir mmap sur linux et CreateFileMapping sur Windows).

en gros, une zone mémoire virtuelle est créée pour correspondre a ton fichier. si tu lit/écrit dans cette zone, ca lit/écrit automatiquement dans le fichier.
C'est d'ailleurs utilisé pour faire une copie rapide d'un fichier dans un autre: ou fait deux projections mémoire (fichier source et destination) puis un simple memcopy et c'est tout. (https://c.happycodings.com/gnu-linux/code6.html et http://world.std.com/~jmhart/cpmm.htm )

l'astuce est que le système d'exploitation n'alloue pas la totalité de la mémoire et ne charge le fichier qu'en fonction de tes besoins.


-
Grou29
http://lienssanslien.free.fr
0
je suis débutant et on ma dit qu'il ne faut pas trop peneter dans la programation WINDOWS (rester dans les normes)car sa ne sert a rien
0
une faute dans mon code
au lieu de

if(strstr2(buf,n-tailleMot,mot))
{
return true;
}

il faut mettre

if(strstr2(buf,n-tailleMot,mot))
{
fclose(file);
return true;
}
0