Comme le titre l'indique, je voudrais rajouter une ligne en d�but d'un
fichier texte. J'ai beau parcourir dans tous les sens le manuel sur
"open" "puts" et "file", je n'arrive pas � trouver un moyen d'y arriver.
Quelqu'un aurait une id�e ?
--
Clipper, qui, d'habitude, trouve la solution presque imm�diatement apr�s
avoir post�.
--
David Zolli
D'accord. Si je comprends bien tout, en fait on ne peut pas se d�placer
dans un fichier et rajouter des lignes, donc on cr�e un nouveau fichier
avec la ligne, puis on y ajoute le contenu de l'ancien fichier.
j'y avais pens� mais je me disais qu'il pouvait y avoir une subtilit�
quelque part que je n'avais pas vue et qui permettait de faire mieux.
merci pour cette r�ponse.
--
Clipper
Quelque soit le langage, pour écrire dans un fichier,
on est obligé de le monter en mémoire. Autrement dit
de le mettre dans une variable.
Le mécanisme qui consiste à concaténer la ligne à ajouter
et le reste du fichier est nettement visible avec Tcl,
mais il en est de même dans d'autres langages.
Sauf que parfois ce mécanisme est masqué par la syntaxe du langage.
Pour insérer une ligne dans un fichier texte à la nième
ligne, la meilleure stratégie reste de mettre le contenu
fichier dans une variable, de faire un "split" sur les
retours chariot ("\n") et d'insérer la ligne avec linsert.
Si l'on veut naviguer plus finement, il existe la commande "seek".
Mais elle est utilisé au niveau des octets et pas des caractères.
GS
set fin [open $fichier p] ; # avec p = prepend comme a = append
ça ne serait pas une mauvaise idée.
--
David Zolli
oui, hein, �a pourrait �tre pratique !
--
Clipper
Pour ajouter une ligne en début de fichier avec la commande "seek":
set f [open monfichier.txt a]
seek $f 0 start
puts $f "La première ligne"
close $f
Pour faire la même chose en fin de fichier:
seek $f 0 end
GS
Gerard Sookahet a �crit :
> Bonsoir,
>
> Pour ajouter une ligne en d�but de fichier avec la commande "seek":
>
> set f [open monfichier.txt a]
> seek $f 0 start
> puts $f "La premi�re ligne"
> close $f
>
C'est incorrect. Si un fichier est ouvert avec le mode "a", toutes les
ecritures sont effectuees a la fin du fichier, peu importe quel etait la
position du curseur juste avant le [puts] (donc le seek ci-dessus n'a
aucun effet sur ce que fait le puts, et "La premiere ligne" est ecrite
en fin de fichier).
En ouvrant le fichier en mode "r+", le code ci-dessus permettrait
d'ecrire la ligne "La premiere ligne " en tete de fichier, mais en
ecrasant le contenu precedent du fichier, et non en l'inserant
(intercalant) avant le contenu.
Quant au mode "p" sorti de l'imagination de David, je rappelle juste
(comme l'a deja evoque Gerard) que sa non-existence ne resulte pas d'une
fonctionnalite manquante dans Tcl, mais juste dans le fait que quasiment
aucun systeme de fichiers (filesystem) n'est concu pour permettre cette
operation.
La lecture en memoire, puis reecriture du contenu, est la methode
triviale, la plus facile a mettre en oeuvre. Cependant, si le fichier
est large, cela peut couter cher, voire etre impossible (essayer donc de
charger un le contenu d'un .iso de 4.7G dans une chaine Tcl, surtout sur
un systeme 32bits :p). Autre probleme de cette approche, si
quelquechose se passe mal pendant la copie, le contenu du fichier est
perdu. L'autre solution intuitive est donc de passer par un fichier
temporaire, puis d'ecraser le fichier original une fois le fichier
temporaire complet. Mais la, ca peut couter cher sur le disque dur.
Reste donc la solution de faire le decalage du fichier en place, par
exemple avec le code ci-dessous.
Eric
-----
Eric Hassold
Evolane - http://www.evolane.com/
-----
# Ecriture dans un fichier par insertion (en tete ou au milieu du
# fichier), sans lire le contenu du fichier en RAM, ni utiliser
# de copie temporaire, afin de permettre de travailler avec des
# fichiers larges
proc finsert {f buf {where 0}} {
# Open file
set fd [open $f r+]
fconfigure $fd -translation binary -encoding binary
if {$where>0} {
seek $fd $where start
}
# On se souvient de ou inserer le tampon $buf
set pstart [tell $fd]
# Ajuste la taille du fichier a la taille finale
seek $fd 0 end
set p0 [tell $fd]
puts -nonewline $fd $buf
set p1 [tell $fd]
# Decalage a appliquer
set shift [expr {$p1-$p0}]
# Memoire a utiliser pour la copie. Inutile de monter trop,
# ce qui n'apporterait aucun gain en performance, mais
# ne pas utiliser une valeur ridiculement petite, pour eviter
# les coups des [seek]
set bsize [expr {1024*1024}]
# Taille du bloc a deplacer (en octets)
set tomove [expr {$p0-$pstart}]
# Decalage
set done 0
while {$done<$tomove} {
set p [expr {$p0-$bsize}]
if {$p<$pstart} {
set p $pstart
}
set tmplen [expr {$p0-$p}]
seek $fd $p start
set tmp [read $fd $tmplen]
seek $fd [expr {$p+$shift}]
puts -nonewline $fd $tmp
set p0 $p
incr done $tmplen
}
# Ecriture du buffer a sa position cible
seek $fd $pstart
puts -nonewline $fd $buf
# That's all folks
close $fd
return
}
# Insertion en tete n'est qu'un cas particulier
proc prepend {f buf} {
return [finsert $f $buf 0]
}
# Pour inserer une ligne en tete du fichier toto.txt
# prepend toto.txt "Hello\n"
En plus, comme les données des fichiers n'ont plus besoin d'être
écrites consécutivement sur le disque depuis qu'on a des tables
d'allocation à peut près potables, un vrai prepend ne devrait pas être
insurmontable (mais c'est un autre sujet).
--
David Zolli
Eric Hassold a �crit :
>
> La lecture en memoire, puis reecriture du contenu, est la methode
> triviale, la plus facile a mettre en oeuvre. Cependant, si le fichier
> est large, cela peut couter cher, voire etre impossible (essayer donc de
> charger un le contenu d'un .iso de 4.7G dans une chaine Tcl, surtout sur
> un systeme 32bits :p). Autre probleme de cette approche, si
> quelquechose se passe mal pendant la copie, le contenu du fichier est
> perdu. L'autre solution intuitive est donc de passer par un fichier
> temporaire, puis d'ecraser le fichier original une fois le fichier
> temporaire complet. Mais la, ca peut couter cher sur le disque dur.
Peut-�tre que la solution s�re consiste alors � utiliser la
concat�nation de fichiers en passant par une commande externe, genre :
echo ligne_a_ajouter > f1
cat f1 f2 > f3
On a ajout� ainsi la ligne dans f2 et enregistr� cela dans f3
Sous Win, je crois me souvenir qu'on peut concat�ner en faisant copy
f1+f2 f3
Evidemment, on doit ensuite effacer f2 et renommer f3 en f2.
Bon, on n'est plus dans une solution tcl, je sais ;-)
Amicalement, Vincent Verdon
sinon il y a aussi dans le package fileutil de la librairie tcl la
commande
::fileutil::insertIntoFile
Je suppose que l'algorithme doit ressembler à celui d'Eric. L'idée de
Kroc de reprendre cet algorithme en C est intéressante.