tac
est lui-même un programme assez simple - vous pouvez simplement implémenter son algorithme dans Tcl, au moins si vous êtes déterminé à lire littéralement chaque ligne dans l'ordre inverse. Cependant, je pense que cette contrainte n'est pas vraiment nécessaire - vous avez dit que le contenu que vous recherchez est plus susceptible d'être proche de la fin qu'au début, pas que vous deviez scanner les lignes dans l'ordre inverse. Cela signifie que vous pouvez faire quelque chose d'un peu plus simple. Grosso modo:
- Recherche d'un décalage près de la fin du fichier.
- Lire ligne par ligne comme d'habitude, jusqu'à ce que vous atteigniez des données que vous avez déjà traitées.
- Recherche d'un décalage un peu plus éloigné de la fin du fichier.
- Lire ligne par ligne comme d'habitude, jusqu'à ce que vous atteigniez des données que vous avez déjà traitées.
- etc.
De cette façon, vous n'avez pas vraiment de garder quelque chose de plus en mémoire que la seule ligne que vous traitez en ce moment, et vous traitez les données à la fin du fichier avant données plus tôt dans le fichier. Peut-être pourriez-vous améliorer un peu plus les performances en traitant strictement les lignes dans l'ordre inverse, mais je doute que ce soit important par rapport à l'avantage que vous obtenez en ne numérisant pas du début à la fin.
Voici un exemple de code qui implémente cet algorithme. Notez le peu de soin apporté pour éviter de traiter une ligne partielle:
set BLOCKSIZE 16384
set offset [file size $filename]
set lastOffset [file size $filename]
set f [open $filename r]
while { 1 } {
seek $f $offset
if { $offset > 0 } {
# We may have accidentally read a partial line, because we don't
# know where the line boundaries are. Skip to the end of whatever
# line we're in, and discard the content. We'll get it instead
# at the end of the _next_ block.
gets $f
set offset [tell $f]
}
while { [tell $f] < $lastOffset } {
set line [gets $f]
### Do whatever you're going to do with the line here
puts $line
}
set lastOffset $offset
if { $lastOffset == 0 } {
# All done, we just processed the start of the file.
break
}
set offset [expr {$offset - $BLOCKSIZE}]
if { $offset < 0 } {
set offset 0
}
}
close $f