A voir également:
- Chercher une chaine dans un fichier (c++)
- Fichier rar - Guide
- Comment ouvrir un fichier epub ? - Guide
- Comment réduire la taille d'un fichier - Guide
- Ouvrir un fichier .bin - Guide
- Fichier host - Guide
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
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.
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.
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):
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; } }
[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)
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; } }
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
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
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
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
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
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
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