Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1420 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Supprimer derniere ligne d'un fichier SANS le parcourir

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Supprimer derniere ligne d'un fichier SANS le parcourir

n°2286988
xfreekingx
Posté le 27-08-2016 à 12:28:10  profilanswer
 

Bonjour tout le monde ,  :hello:  
 
Je recherche une solution afin de pouvoir supprimer la dernière ligne d'un fichier (.txt ou autre) en C. Le problème est que je ne connais par avance, ni la taille du fichier, ni la longueur de la dernière ligne... Le fichier pouvant faire plusieurs Go, il est hors de question de parcourir chaque lignes jusqu’à la dernière...
 
Du coup je m’étais dis que je pourrais peut-être me placer directement à la fin du fichier (avec fseek() ) puis remonter jusqu'au dernier '\n' et écraser tout ce qui suit avec des " " ( du style : fprinf(monFichier,"                                                                                                                                                      " );     ). C'est un peu "sale" mais bon... :D
 
Comment puis-me placer au début de la dernière ligne ?
Connaissez-vous une façon moins "sale" de supprimer la dernière ligne sans parcourir tout le fichier ?
 
Merci pour votre aide :)

mood
Publicité
Posté le 27-08-2016 à 12:28:10  profilanswer
 

n°2286991
gilou
Modérateur
Modzilla
Posté le 27-08-2016 à 14:13:00  profilanswer
 

Si tu sais que ta dernière ligne n’excède pas une certaine longueur K, tu peux te positionner a K octets de la fin, copier les K derniers octets de ton fichier dans un buffer, y calculer la position du dernier \n et en déduire à quelle longueur tu dois tronquer ton fichier.
Ça suppose néanmoins que fseek positionné par rapport à la fin ne parcourt pas tous le fichier pour y aller, ce qui peut ne pas être le cas si ton implem de fseek n'est pas optimisée.
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2286993
xfreekingx
Posté le 27-08-2016 à 14:36:30  profilanswer
 

Merci pour votre réponse :)
 
Je viens de faire le code en C et ca fonctionne nikel. J'en ai profité pour récupérer la dernière ligne avant de la supprimer ^^

n°2286994
gilou
Modérateur
Modzilla
Posté le 27-08-2016 à 14:52:27  profilanswer
 

Faut faire juste gaffe au cas limite du fichier de taille < K
Comme de toute façon tu connais la taille du fichier, c'est pas couteux de tester.
 
A+,


Message édité par gilou le 27-08-2016 à 14:53:24

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2286997
xfreekingx
Posté le 27-08-2016 à 15:55:06  profilanswer
 

Bon... Ben en faite, je ne sais pas pourquoi mais j'ai une erreur ( 0x0000005) avec mon code :cry: . Le printf("Debug\n" ); indique le dernier moment avant le bug. Le printf("Debug\n" ); indique celui qui ne s'affiche pas. Donc visiblement l'erreur arrive au niveau ma boucle "do...While"...
 
Je répète que je ne connais pas la taille de mon fichier, ni son nombre de lignes, ni la taille de la dernière ligne ^^
 
voici mon code :
 

Code :
  1. long position = 0;                                             
  2.                 long DebutDerniereLigne = 0;                                             
  3.                 static const long max_len = 128 + 1;   
  4.                 char buff[max_len + 1];                                     
  5.                 fseek(fichier, -max_len, SEEK_END);
  6.                 fread(buff,max_len-1,1,fichier);
  7.                 buff[max_len-1] = '\0';
  8.                 char *last_newline = strrchr(buff, '\n');
  9.                 char *last_line = last_newline+1;
  10.                 char derniereLigne[128] = "";                 
  11.                 int i =0;
  12.                 printf("debug\n" );
  13.                 do
  14.                 {
  15.                     //printf("%d\n",i);
  16.                     derniereLigne[i] = last_line[i];
  17.                     i++;
  18.                 }while(last_line[i] != '\0');
  19.                 printf("debug\n" );


 
Je ne comprends pas comment je peux avoir une erreur d'accès mémoire... J'ai testé avec "while...do" et  while(last_line[i-1] != '\0');   ou   while(last_line[i+1] != '\0'); et c'est exactement pareil, mon printf("%d\n",i); écrit 0, puis ca plante...
 
Qqun a-t'il une solution ? Je comprends pas la :heink:  
 
Merci pour votre aide

n°2286998
rat de com​bat
attention rongeur méchant!
Posté le 27-08-2016 à 17:47:18  profilanswer
 

Tu l'ouvres comment ton fichier? Sous Windows en tout cas je dois mettre fopen(..., "rb" ). Après il y a des +1/-1 en trop/inutiles. Par contre si le fichier est trop court --> BOUM. Un peu de gestion d'erreur (fseek, fread, strrchr) ne serait pas une mauvaise idée.
 
Code sur demande.

n°2287000
xfreekingx
Posté le 27-08-2016 à 22:50:09  profilanswer
 

Effectivement, en ouvrant le fichier en "rb+" c'est mieux  :jap:  
J'ai fini par y arriver en utilisant une méthode un peu "dégeux" ^^, mais c'est toujours mieux que de parcourir encore et encore tout un fichier de plusieurs dizaines de Go :)
 
Voici mon code ( qui fonctionne bien, en tous cas j'ai pas encore eu d'erreur :whistle: et je l'ai testé sur plusieurs fichiers de plusieurs formats et différentes tailles )  :
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int main()
  5. {
  6.     FILE* fichier = NULL;
  7.     fichier = fopen("AEF-2015.pdf","rb+" );
  8.     if(fichier != NULL)
  9.     {
  10.         printf("Le fichier est ouvert en rb+...\n" );
  11.         fseek(fichier,-1,SEEK_END);                           // Je me place a l'avant-dernier caractère du fichier pour éviter de tomber                                                                    //directement sur EOF dans ma prochaine boucle
  12.         int caractereActuel =0;
  13.         int i =0;
  14.         do
  15.         {
  16.             caractereActuel = fgetc(fichier);
  17.             i++;
  18.             fseek(fichier,-2,SEEK_CUR);
  19.         } while (caractereActuel != '\n');                      // je parcours mon fichier a l'envert en partant de la fin et je compte la                                                                    //taille de ma derniere ligne => jusqu'a tomber sur un '\n'.
  20.         int c = 0;
  21.         char tab[512] = "";
  22.         for(c=0;c<i+1;c++)                          // A partir du début de ma dernière ligne, je récupère autemps de caractères que la                                                              //taille de ma ligne => toute ma derniere ligne sans le EOF
  23.         {
  24.             tab[c] = fgetc(fichier);
  25.         }
  26.         fseek(fichier,-i,SEEK_CUR);               // Je me replace au début de ma dernière ligne
  27.         do
  28.         {
  29.             fputc(' ',fichier);                  // Je re-parcours ma dernière ligne en remplaçant tous les caractères par des 'ESPACE'                                                             //(ici j'aurai préféré la supprimer mais bon...c'est mieu que rien XD)
  30.             i--;
  31.         } while (i != 0);
  32.         printf("La Derniere ligne est : %s\n",tab);       // Et voila ! tab contient ma derniere ligne et ma derniere ligne a disparut !
  33.         fclose(fichier);
  34.         printf("Le fichier est ferme...\n" );
  35.     }
  36.     else
  37.     {
  38.         printf("Le fichier est introuvable...\n" );
  39.     }
  40.     return 0;
  41. }


 
Voila, au final ce programme fait a peu prés ce que je voulais, cad : Lire la dernière ligne, et la supprimer (la faire disparaître visuellement)  :sol: . Bien sur, si je pouvais tout simplement supprimer la dernière ligne ce serait mieux, mais bon, c'est déjà bien comme ca.
 
Bonne soirée a tous  :hello:

n°2287740
suiL
Posté le 12-09-2016 à 01:33:00  profilanswer
 

Tu pourrais utiliser un buffer correspondant a la taille de ton fichier,  et récupérer l'avant dernier \n et delete tout entre le \n et la fin de ton buffer

n°2287754
masklinn
í dag viðrar vel til loftárása
Posté le 12-09-2016 à 10:25:55  profilanswer
 

suiL a écrit :

Tu pourrais utiliser un buffer correspondant a la taille de ton fichier,  et récupérer l'avant dernier \n et delete tout entre le \n et la fin de ton buffer


Si le fichier fait plusieurs dizaines de Go c'est pas trop une option. Sur plateforme 64b tu peux mmapper le fichier par contre, c'est à ça que ça sert. Et tu voudras dans tous les cas appliquer le même processus d'itérer les caractères en partant de la fin histoire de pas te taper 10Go de truc dont tu te fous, donc ça va pas faire une grosse différence.

 

Si les lignes sont très très longues tu peux charger tes données dans un petit buffer (16 octets) pour pouvoir vectoriser la recherche, mais bon c'est beaucoup de complexité pour probablement pas grand chose.


Message édité par masklinn le 12-09-2016 à 10:31:51

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°2290429
rat de com​bat
attention rongeur méchant!
Posté le 19-10-2016 à 23:25:39  profilanswer
 

xfreekingx a écrit :

Bien sur, si je pouvais tout simplement supprimer la dernière ligne ce serait mieux, mais bon, c'est déjà bien comme ca.

Quel compilateur? Avec MinGW on peut utiliser ftruncate() mais c'est pas dans la lib standard C.
 
Le code suivant est juste un "proof of concept" sans garantie, à tester/améliorer/adapter/...

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <strings.h>
  4. #include <unistd.h>
  5.  
  6. //copié de stdio.h (pourtant inclus) pour eviter un warning undefined function, pas compris...
  7. #define fileno(__F) ((__F)->_file)
  8.  
  9. #define MAX_LEN 128 //A ADAPTER
  10.  
  11. int main(void)
  12. {
  13.    FILE * fichier = fopen("test.txt", "r+b" );
  14.  
  15.    if(!fichier)
  16.    {
  17.        puts("err fopen" );
  18.        return 1;
  19.    }
  20.  
  21.    char buff[MAX_LEN + 1];
  22.    
  23.    fseek(fichier, 0, SEEK_END);
  24.    
  25.    int taille=ftell(fichier);
  26.    
  27.    printf("taille fichier: %d\n", taille);
  28.    
  29.    fseek(fichier, -MAX_LEN, SEEK_END);
  30.    
  31.    fread(buff,MAX_LEN,1,fichier);
  32.    
  33.    buff[MAX_LEN] = '\0';
  34.    
  35.    char *last_newline = strrchr(buff, '\n');
  36.    if(!last_newline)
  37.    {
  38.        puts("err strrchr, derniere ligne trop longue?" );
  39.        return 1;
  40.    }
  41.    
  42.    char *last_line = last_newline+1;
  43.    
  44.    char derniereLigne[MAX_LEN] = "";
  45.    
  46.    strncpy(derniereLigne, last_line, MAX_LEN);
  47.  
  48.    printf("ligne: \"%s\"\n", derniereLigne);
  49.  
  50.    printf("longeur ligne: %d\n", strlen(derniereLigne));
  51.  
  52.    fflush(fichier);
  53.    
  54.    if(ftruncate(fileno(fichier), taille - strlen(derniereLigne)-2))
  55.    {
  56.        puts("err ftruncate" );
  57.        return 1;
  58.    }
  59.  
  60.    fclose(fichier);
  61.  
  62.    return 0;
  63. }


(Oui j'aime bien le code aéré. :o )
 
Mais euh... Ce genre de truc sur un pdf???

Citation :

Code :
  1. fichier = fopen("AEF-2015.pdf","rb+" );



Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Supprimer derniere ligne d'un fichier SANS le parcourir

 

Sujets relatifs
Extraction d'une valeur d'un fichier via un batchlecture et écriture dans un fichier
[BATCH] utiliser %%A et ignorer l'extension fichier (RESOLU)Comment faire un saut de ligne (noob) ?
[RESOLU] [wordpress] protéger des fichier HTMLRécupérer le dernier "bloc" de chaque ligne d'un fichier
Copie de fichier dans des sous répertoires aléatoires multiples[récupération de fichier]
Comment exporter une feuille dans un nouveau fichier 
Plus de sujets relatifs à : Supprimer derniere ligne d'un fichier SANS le parcourir


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR