2010-11-05 4 views
2

Je souhaite lire à rebours ligne par ligne à partir d'un fichier gzippé. Je connais le module ReadBackwards, mais comment puis-je le faire fonctionner sur un fichier compressé? Y a-t-il un module différent que je devrais utiliser?Perl Lecture en différé et fichiers gzippés

+2

Les réponses jusqu'à présent ont expliqué pourquoi vous ne pouvez pas faire ce que vous voulez. Il peut y avoir d'autres options; Pouvez-vous fournir plus de détails sur votre objectif réel, quel genre de choses sont dans les fichiers, pourquoi est-ce que vous ne pouvez pas dire combien vous avez besoin jusqu'à ce que vous le voyiez? Par exemple, une approche en deux passes pourrait-elle fonctionner? – Porculus

+0

@Poculus - une approche en deux passes fonctionnerait. Cependant, j'ai fini par prendre l'approche de chas. Mon problème était que j'avais de très gros fichiers journaux, qui contenaient des messages relatifs à plusieurs sujets différents.Pour chaque sujet, j'ai besoin de saisir la ligne juste avant la dernière ligne sur laquelle une condition (une regex compliquée) était vraie. Cela signifiait souvent que je devais lire pas plus de 1-2% de la fin du fichier, mais de temps en temps, je lisais 10-20% à partir du bas et dans le pire des cas, je devais jusqu'à 50% du fichier. –

Répondre

7

Pourquoi voulez-vous le lire à l'envers? Il n'y a pas d'amélioration des performances en essayant de lire un fichier compressé à l'envers. Vous devez d'abord le décompresser (pour comprendre quel octet n signifie que vous devez d'abord décompresser octets 0 .. n).

Vous n'êtes probablement pas aller mieux en termes de vitesse que:

#!/usr/bin/perl 

use strict; 
use warnings; 

die "usage: $0 filename" unless defined(my $file = shift); 

open my $fh, "<:gzip", $file 
    or die "could not open $file: $!"; 

my @lines; 
while (<$fh>) { 
    push @lines, $_; 
    shift @lines if @lines > 10; 
} 

print @lines; 
+0

Je m'en fiche si la recherche de la fin est lente. Ce que je voulais éviter était de stocker tout le fichier en mémoire. Je ne sais pas jusqu'à ce que je les ai traitées combien de lignes dont j'ai besoin. Je n'ai pas, en particulier, la garantie que je n'aurai pas besoin de lire tout le dossier. –

+0

métaphore @pythonic Vous aurez besoin de décompresser dans un fichier, puis utilisez 'File :: Backwards' pour le lire. –

4

Vous allez devoir décompresser le fichier en premier. Vous ne pouvez pas (facilement) chercher dans un fichier gziped au hasard.

+0

Je suis dans la situation où les fichiers pertinents sont assez gros, plusieurs gb pour être précis, et je ne sais pas combien de lignes je vais devoir traiter à partir du bas à l'avance. –

+1

@pythonic alors il n'y a aucun moyen de faire ce que vous voulez qui n'est pas très, très lent. gzip avec des réinitialisations de flux périodiques est marginalement possible (pas à partir de PerlIO, mais vous pouvez écrire du code qui l'utilise). gzip * sans * réinitialisations de flux périodiques est 100% insaisissable, et c'est probablement ce que vous avez. – hobbs

0

Ne pas stocker le fichier dans la mémoire. Stockez-le dans une base de données SQLite ou similaire, avec un champ d'index séquentiel du numéro de ligne tel qu'il a été lu et inséré dans la base de données. Lorsque le fichier est complètement stocké dans la base de données, parcourez les lignes en triant l'index à l'aide d'un tri décroissant. Vous pouvez rapidement parcourir la base de données si nécessaire, en plus vous pouvez utiliser des requêtes de base de données pour trouver des lignes. Ce ne sera pas aussi rapide que si vous aviez beaucoup de RAM ou d'un disque SSD, mais ce sera beaucoup plus rapide que d'essayer de traiter un fichier compressé comme vous en parlez.

La programmation informatique consiste à trouver des solutions créatives tout en respectant les limites. Vous êtes limité par la RAM et le fait que vous travaillez avec des fichiers compressés. Vous devez décompresser le fichier pour revenir en arrière, mais vous ne pouvez pas l'insérer dans la RAM. Donc, vous devez mettre les données quelque part, et cela laisse à peu près le disque. Il est plus facile de revenir en arrière dans une base de données que dans un fichier plat. Utilisez donc la base de données pour savoir à quoi elle sert et passez à autre chose.

0

Je n'ai pas une bonne méthode pour tester, mais de this post je pense que vous pouvez ouvrir le fichier avec

open my $handle, '-|', '/usr/bin/gzcat', $filename; 

Cela vous permettra de faire un pas dans la ligne par ligne comme fichier Ma compréhension est que cela ne slurp pas le fichier entier et devrait aider avec la mémoire sur le fichier volumineux. Si je me trompe, j'espère que quelqu'un viendra me gifler avec un poisson. Je sais aussi que cela va de l'avant, mais mon espoir pour vous est que vous n'aurez plus besoin de revenir en arrière du point de vue de la mémoire. Si vous le faites peut-être, vous pouvez faire quelques modifications pour l'utiliser avec File :: Backwards.

Maintenant, je ne semble pas avoir gzcat sur mon système (Ubuntu), bien que je trouve beaucoup de références qui disent que gzcat est le même que zcat ou gunzip -c ou gzip -dc ainsi de suite le nom du programme YMMV. Encore une fois, j'espère que la méthode est solide.

Questions connexes