Insérer une ligne dans un fichier texte [Résolu/Fermé]

Signaler
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
-
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
-
Bonjour,

Voilà ce que mon programme doit faire :

1) Ouvrir un fichier texte externe.
1-bis) Copier ou dupliquer le fichier si besoin.
2) Insérer une nouvelle ligne entre la première et la deuxième ligne, sans modifier la structure du texte.
3) Fermer le fichier

Voilà une partie de mon fichier texte à modifier
V5.0******************************** COMMON DATA *******************************Modification date :  09/05/2012
THERMOPHYSICAL PROPERTIES OF THE METAL *****************************************
dynamic viscosity of the liquid (kg/m/s) ..................|+1.00000E+00|visc
density (kg/m3) ...........................................|+1.00000E+00|ro
total volumic coefficient in the mushy zone (/K)...........|+1.00000E+00|betatot
number of points defining the curve beta=f(T) .............|    2       |nbetas
for each point, temperature (°C)...........................|+1.00000E+00|tem(k)
                linear thermal expansion coefficient (/K)..|+1.00000E+00|betas(k)
for each point, temperature (°C)...........................|+1.00000E+00|tem(k)
                linear thermal expansion coefficient (/K)..|+1.00000E+00|betas(k)
molecular weight of the metal (kg/mol) ....................|+1.00000E+00|asmol
specific heat (J/kg/K) ....................................|+1.00000E+00|cp
volumic thermal expansion coefficient of the liquid (/K)...|+1.00000E+00|beta
number of points defining the curve lambda=f(T) ...........|    2       |nlambda
[...]


La contrainte est que je ne dois pas faire du copier/coller ligne par ligne, vu le nombre de fichier à traiter et le nombre de lignes de chaque fichier, on perd du temps avec cette méthode.

Hormis la méthode du copier/coller ligne par ligne que je peux faire dans C, C++, Windev, JAVA ... je ne connais pas d'autres solutions, et je dois en trouver ou être sûr qu'il y en a pas.

Le choix du langage de programmation importe peu, alors si vous avez une idée sur ça, je suis preneur.

Je vous remercie de vos réponses et je m'excuse si je ne suis pas clair dans mon message alors n'hésitez pas à me demander des infos en plus.




16 réponses

Messages postés
759
Date d'inscription
mercredi 17 juin 2009
Statut
Membre
Dernière intervention
29 décembre 2013
121
Pour manipuler des fichiers avec des programmes, il faut déjà bien comprendre ce qu'est physiquement un fichier, c'est à dire ce qu'est un fichier en mémoire (en RAM, sur disque dur, sur clé USB, etc)
Au niveau le plus proche du matériel, physiquement, un fichier c'est une suite de bits, une succession ininterrompue et monotone de signaux physiquement inscrits sur un support, mais qu'il n'y a rien qui corresponde physiquement à une ligne.

Ensuite à un niveau un peu au dessus matériel, il y a l'organisation conventionnelle de ces bits. Ils ne sont pas organisés de façon quelconque mais sous forme de bytes, c'est à dire d'unité adressables en mémoire.

A un niveau encore un peu au dessus, il y a la signification conventionnellement accordée à chacune des valeurs inscrites (sous forme de bits) dans les bytes.
Quand il s'agit de fichier dit texte, les valeurs des bytes codent en fait pour deux types de significations: certaines valeurs de byte codent pour des caractères, c'est à dire qu'un moteur de rendu d'affichage interprétera les bytes-caractères pour en déduire quels sortes de glyphes afficher à l'écran;
tandis que les bytes non-caractères ont d'autres significations et servent à exprimer des besoins différents de ceux de l'affichage de glyphes. Ainsi, en ASCII toutes les valeurs de bytes comprises entre 0 et 31 codent pour autre chose que des caractères.

Parmi les bytes non-caractères, il y a ceux qui ont pour rôle de signaler au moteur de rendu d'affichage qu'il faut passer à la ligne suivante: ce sont la valeur de byte symbolisée par \r et la valeur de byte symbolisée par \n.
On les représente avec un antislash parce qu'on est bien obligé de trouver un moyen de représenter par des caractères des valeurs de bytes qui ne codent pas pour des caractères.

Sous Windows, le codage des fins de lignes se fait par le groupe des deux codes \r\n accolés.




Tout ce laüs est destiné à faire comprendre qu'en ayant la notion qu'un fichier est une succession de bytes et que des lignes sont seulement un effet visuel obtenu à l'écran lors de l'affichage du fait de la présence de certaines valeurs de bytes rencontrées dans cette succession, on est plus à même d'imaginer tout seul comment on va pouvoir obtenir telle ou telle manipulation de fichier, sans devoir faire appel à d'autres personnes.

Dans ton cas, tu veux insérer quelque chose entre la première ligne et le reste des lignes. Ça, c'est la représentation intellectuelle de ce qui est voulu.
Au niveau physique, on est obligé de prendre conscience qu'on ne va pas pouvoir écarter les bits qui constituent la représentation de la première ligne et les bits qui constituent les lignes suivantes et y déposer des bits représentant l'ajout qu'on veut faire.
On va être obligé de lire et de réécrire des bytes, soit en décalant des valeurs sur des bytes proches et d'une façon qu'on va contrôler soi-même, soit on réécrit l'entièreté d'un fichier modifié et c'est le système d'exploitation qui se charge de savoir comment le faire et où mettre le nouveau fichier.

Dans le fichier initial, les bytes qui représentent la première ligne et ceux qui représentent les lignes suivantes sont séparés par le couple de bytes de valeurs \r\n.
Le point clé que je voulais ammener, c'est qu'il est plus pratique de se représenter que la première ligne est constituée de la succession de bytes jusqu'au premier couple \r\n rencontré et que les autres lignes sont la succession de bytes qui se trouvent au delà sans se préoccuper d'y distinguer des lignes.







Maintenant, au niveau de l'outil qui va permettre de faire un traitement donné sur un fichier, il est certain qu'il ne faut pas choisir d'utiliser le langage assembleur et de vouloir intervenir au niveau le plus bas, c'est à dire des bits. Ce serait monumentalement douloureux et long.
C'est pour s'affranchir de cette pénibilité qu'ont été inventés des langages d'un niveau un peu au dessus, par exemple le C.
Mais même le C est encore trop proche de la machine pour permettre de faire ce qu'on veut avec aisance. Il faut choisir un outil plus proche de l'esprit humain que le C.
Excel n'est pas un bon choix. On est contraint de l'utiliser de la manière pour laquelle il a été prévu, on ne peut pas le plier à des besoins spécifiques. Tout simplement, ce n'est pas un langage de programmation, c'est un langage de macros, pas conçu pour permettre des choses complexes.

Il faut un langage de programmation qui donne la possibilité de concrétiser en un logiciel les idées qu'on peut avoir pour obtenir tel ou tel traitement sur un fichier, compte tenu de la compréhension qu'on a de ce fichier, et sans s'enquiquiner à devoir gérer des choses au niveau matériel comme le fait le C.

Personnellement, pour cela, j'utilise Python, qui est un langage de haut niveau, c'est à dire dont l'utilisation ne nécessite pas de se préoccuper de caractéristiques liées à la machine et de la gestion des bytes.


Pour réécrire un fichier avec insertion d'un ajout entre la première ligne et le reste du fichier, il suffit en Python de faire:
chemin_de_fichier = 'C:\\Exos Python\\metallica.txt'

with open(chemin_de_fichier,'r') as fr:
    ch = fr.read()

# p = position du premier couple d'octets de valeurs \r\n
# p+2 est la position du premier octet juste après le couple \r\n
p = ch.find('\r\n') + 2

with open(chemin_de_fichier,'w') as fw:
    fw.write(ch[0:p])
    fw.write(ajout)
    fw.write(ch[p:])


Ce n'est pas la seule façon de faire mais celle-ci suffit à montrer qu'il est très simple de rédiger un programme pour faire ce que tu veux, et qu'il est très simple de le comprendre.

Tandis qu'avec Excel, il faut concevoir une macro et ça n'a pas l'air d'enthousiasmer grand monde de la faire.
Quant à sed, c'est peut être bien pour faire quelque chose de limité mais ça n'a pas l'aptitude d'être adapté pour étendre à des besoins plus complexes.

A partir du code ci-dessus , il est facile d'étendre les opérations pour obtenir un traitement automatisé de tout un réperoire, ou de tenir compte de certains critères pour différencier les actions sur des fichiers différents.

Python s'installe en moins de 10 minutes sur un ordinateur.
3
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 60511 internautes nous ont dit merci ce mois-ci

Messages postés
8700
Date d'inscription
dimanche 8 avril 2007
Statut
Contributeur
Dernière intervention
22 janvier 2020
1 120
Bonjour,
Sans savoir les terminaisons des lignes du fichier c'est difficile de te proposer une solution (si existe)
Tu pourais déposer ton fichier sur Cjoint.com ou similaire ?
Même rien que le début du fichier, une ou deux dizaines de lignes.
A+
Si tu te cognes à un pot et que ça sonne creux, c'est pas forcément le pot qui est vide. ;-)(Confucius)
NOTE : Je ne répond pas aux MP pour les questions techniques.
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Voilà l'adresse du fichier comme demandé :

http://cjoint.com/data/0EqnIMN4MNx.htm
Messages postés
8700
Date d'inscription
dimanche 8 avril 2007
Statut
Contributeur
Dernière intervention
22 janvier 2020
1 120
Ton fichier en retour
Regarde si le fichier est toujours compatible avec ton appli, je pense que oui.
Tu a Excel ?
A+
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Oui j'ai Excel
Messages postés
8700
Date d'inscription
dimanche 8 avril 2007
Statut
Contributeur
Dernière intervention
22 janvier 2020
1 120
Alors je pense que le plus simple c'est d'ouvrir le fichier avec Excel, insérer une ligne et le sauver. C'est ce que j'ai fais avec ton fichier.
Tu ne dis pas s'il est toujours compatible ?
Avec quel appli est-il traiter, je ne connais pas l'extension "don"
Si tu à vraiment beaucoup de fichier à traiter tu peu faire une macro pour automatiser.
Si tu ne connais pas bien les macros tu dis, je verrais pour t'aidé.
Tu dis..
Si tu te cognes à un pot et que ça sonne creux, c'est pas forcément le pot qui est vide. ;-)(Confucius)
NOTE : Je ne répond pas aux MP pour les questions techniques.
Messages postés
35755
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
9 novembre 2020
5 621
Salut,

Peu importe le programme qui pourra faire ce que tu demandes ?
Y compris une application GNU/Linux (compatible Windows) ?

Zen my nuggets ;-)
Faites un geste pour l'environnement, fermez vos fenêtres et adoptez un manchot.
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Oui, faut juste que ça marche sous Windows.

Messages postés
35755
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
9 novembre 2020
5 621
C'est une ligne vide qu'il faut insérer ?
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Non, elle n'est pas vide
Messages postés
35755
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
9 novembre 2020
5 621
Bon avec "sed for Windows" ça devrait le faire.

Depuis le répertoire contenant les fichiers à modifier, lancer cette commande :

sed -s -i.bak "1a\blablabla" *.don


-s
Permet de traiter chaque fichier individuellement.

-i.bak
Permet de modifier le fichier "sur-place" et d'en faire une copie avec l'extension ".bak"

1a\blablabla
Ajoute (commande "a\") le texte "blablabla" après la ligne "1"

A tester, étant sous GNU/Linux et ne pouvant tester sous Windows.
Messages postés
8700
Date d'inscription
dimanche 8 avril 2007
Statut
Contributeur
Dernière intervention
22 janvier 2020
1 120
Ont peu très facilement automatiser ce processus sur tout un répertoire ou une sélection.
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Voilà une bonne nouvelle. pourrais je avoir la méthode ou des conseils sur ça ?

Merci
Messages postés
3645
Date d'inscription
dimanche 18 mars 2001
Statut
Modérateur
Dernière intervention
15 janvier 2017
905
Installe une version de sed sous Win$
Et utilise par exemple ceci (qui est efectué sous Inix , mais devrait fonctionner à l'identique sous petitmou)
johand@osiris: ~/tmp $ cat data.txt
ligne1
ligne2
ligne3
ligne4
johand@osiris: ~/tmp $ sed -n -i.bak   -e '1 {s/$/\nNouvelle ligne/ ; p };  2,$ p'   data.txt 
johand@osiris: ~/tmp $ cat  data.txt
ligne1
Nouvelle ligne
ligne2
ligne3
ligne4
johand@osiris: ~/tmp $ cat data.txt.bak 
ligne1
ligne2
ligne3
ligne4
Il y a création de fichier .bak.
Tu trouveras ici une version de sed

Il suffit d'écrire un batch qui parcourt les fichiers à modifier
Messages postés
3645
Date d'inscription
dimanche 18 mars 2001
Statut
Modérateur
Dernière intervention
15 janvier 2017
905
Pas besoin d'être admin pour installer sed en principe. Quoiqu'avec PetitMou, il faut s'attendre à tout .
Voici un exemple en C qui fait ce que tu demandes. Il faudrait ajouter des options qui définissent le numéro de ligne à insérer, utiliser getop. Je laisse cela pour t'amuser:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>


#define BUFFSIZE 512
#define LINENUMBER 4
void print_usage(char *progname)
{
  fprintf(stderr, "Usage %s new_string [input_file]\n\tIf no input file, stdin is used and output is stdout.\n", progname );
  return;
}
int main(int argc, char*argv[])
{
  FILE *filein, *fileout ;
  char buffer[BUFFSIZE] ;
  char bakname[BUFFSIZE] ;

  unsigned int namelen, cnt = 1;

  char *line_to_insert = "Une nouvelle ligne" ;

  if (argc < 2)
    {
      print_usage(argv[0]) ;
      return(EXIT_FAILURE) ;
    }

  switch (argc)
    {
    case 2:
      filein = stdin ;
      fileout = stdout;
      break;
   
    case 3:
      line_to_insert = argv[1];
      namelen = strlen(argv[2]);

      strncpy(bakname, argv[2], BUFFSIZE - 1);
      strncat(bakname, ".bak", BUFFSIZE - namelen - 1);

      if ( ( -1 ==  rename(argv[2], bakname)))
	{
	  perror(NULL);
	  return(EXIT_FAILURE);
	}
      else
	{
	  //should not give errors at least if permissions have not been modified by som other process
	  filein = fopen(bakname, "r");
	  fileout = fopen(argv[2], "w");
	}
      break;   
    }

  fgets(buffer, BUFFSIZE, filein);
  while( !feof(filein) )
    {
      if( (LINENUMBER)  ==  cnt )
	{
	  fprintf(fileout, "%s\n", line_to_insert);
	}

      fprintf(fileout, "%s", buffer);
      fgets(buffer, BUFFSIZE, filein);
      cnt++;
    }
  
  fclose(filein);
  fclose(fileout);
  return(EXIT_SUCCESS);
}
johand@osiris: ~/tmp $ gcc -Wall  -o inserline inserline.c
johand@osiris: ~/tmp $ cp data.org data.txt; ./inserline BLAH data.txt; cat data.txt
Ligne 1
Ligne 2
Ligne 3
BLAH
Ligne 4
Ligne 5
Ligne 6
Ligne 7

Concernant les temps d'exécution un petit test pas très scientifique mais qui montre que le code C reste plus rapide il faudrait avoir un échantillon de fichiers de différentes tailles, jai fait le test comme un goret:
<real	0m7.078s
user	0m0.260s
sys	0m1.292s
johand@osiris: ~/tmp $ time for iter in $(seq 1 1000 ); do cp data.org data.txt; ./inserline BLAH data.txt; done

real	0m6.351s
user	0m0.224s
sys	0m1.288s

Il est clair que sed est plus simple et rapide à mettre en oeuvre.

Johan
Messages postés
759
Date d'inscription
mercredi 17 juin 2009
Statut
Membre
Dernière intervention
29 décembre 2013
121
ça sert à quoi de donner un tel code à quelqu'un qui a l'air très débutant ?
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Oui le fichier est compatible avec mon application, il est traité par plusieurs applications (Windev, Fortran, Tecplot ...)

Au dernier recours, je pensais aussi à des macros que j'utiliserais sous Word même si j'en ai rarement eu l'occasion de faire. Ce que je cherche, c'est de faire un programme qui le fait, comme ça, on peut sélectionner plusieurs fichiers et lancer le traitement (chose que je ne sais pas si on peut la faire avec des macros)

Merci pour ta réponse et ton aide.

Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Merci. Si je peux te poser deux questions bêtes :
1) Je peux avoir un exécutable à la fin ??
2) Penses tu que ça va aller plus vite qu'un programme qui fait du copier/coller ligne par ligne (du coup on a accès à toutes les lignes qu'on veut grâce à un compteur et modifier ou ajouter ce qu'on veut)

L'utilité de la deuxième question est que je suis nul dans le bash, et je n'ai pas eu l'occasion de programmer avec. J'ai peur que ça me prendra du temps à comprendre.

Faut que je trouve l'informaticien pour qu'il me donne l'accès pour installer sed

Merci vraiment pour ta réponse.
Messages postés
8700
Date d'inscription
dimanche 8 avril 2007
Statut
Contributeur
Dernière intervention
22 janvier 2020
1 120
Heuuu, ce topic m'a l'air un "peu" surcharger, décide toi et dis quel solution tu préférerais.
A+
Messages postés
11
Date d'inscription
jeudi 12 avril 2012
Statut
Membre
Dernière intervention
29 mai 2012
4
Merci pour vos réponses ... vous m'avez été d'une grande aide.

Toute fois heyquem m'a bien expliqué le problème, je m'inspirerai de vos programmes pour faire le mien.

Je vais le faire avec mon outil de travail (WinDev), même si ce n'est pas le meilleur pour ce genre de chose, mais au moins; les utilisateurs n'aurons pas à manipuler deux exécutables différents.


Que dois-je mettre ici, pour que ça vaille la peine d'être lu ?!!