2009-12-27 4 views
0

J'ai quelques fichiers .gz compressés qui est d'environ 5-7gig non compressé. Ce sont des fichiers plats.comment puis-je lire un énorme fichier .gz (plus de 5 gig non compressé) en c

J'ai écrit un programme qui prend un fichier non compressé, et le lit ligne par ligne, ce qui fonctionne parfaitement.

Maintenant, je veux être en mesure d'ouvrir les fichiers compressés inmemory et exécuter mon petit programme. J'ai regardé dans zlib mais je ne peux pas trouver une bonne solution.

Le chargement du fichier entier est impossible en utilisant gzread (gzFile, void *, unsigned), à cause de la limitation de 32bit unsigned int.

J'ai essayé gzgets, mais ce double presque le temps d'exécution, vs lecture en utilisant gzread. (Je l'ai testé sur un échantillon 2gig.)

J'ai aussi regardé dans « tampon », comme le fractionnement le processus gzread en plusieurs morceaux de 2gig, trouvez le dernier retour de ligne en utilisant strcchr, puis en définissant le gzseek. Mais gzseek va émuler une décompression totale de fichier. ce qui est très lent.

Je ne vois aucune solution saine à ce problème. Je pourrais toujours faire quelques vérifications, si une ligne courante a réellement une nouvelle ligne (devrait seulement se produire dans la dernière ligne partiellement lue), et puis lire plus de données du point dans le programme où ceci se produit. Mais cela pourrait devenir très moche.

Avez-vous des suggestions?

grâce

modifier: Je ne besoin d'avoir le dossier complet à la fois, juste besoin d'une ligne de temps, mais je suis arrivé une machine assez énorme, donc si tel était le plus facile que je n'aurais aucun problème.

Pour tous ceux qui suggèrent de canaliser le stdin, j'ai connu des ralentissements extrêmes par rapport à l'ouverture du fichier. Voici un petit extrait de code que j'ai fait il y a quelques mois, qui l'illustre.

time ./a.out 59846/59846.txt 
#  59846/59846.txt 
18255221 

real 0m4.321s 
user 0m2.884s 
sys  0m1.424s 
time ./a.out <59846/59846.txt 
18255221 

real 1m56.544s 
user 1m55.043s 
sys  0m1.512s 

Et le code source

#include <iostream> 
#include <fstream> 
#define LENS 10000 

int main(int argc, char **argv){ 
    std::istream *pFile; 

    if(argc==2)//ifargument supplied 
    pFile = new std::ifstream(argv[1],std::ios::in); 
    else //if we want to use stdin 
    pFile = &std::cin; 

    char line[LENS]; 
    if(argc==2) //if we are using a filename, print it. 
    printf("#\t%s\n",argv[1]); 

    if(!pFile){ 
    printf("Do you have permission to open file?\n"); 
    return 0; 
    } 

    int numRow=0; 
    while(!pFile->eof()) { 
    numRow++; 
    pFile->getline(line,LENS); 
    } 
    if(argc==2) 
    delete pFile; 
    printf("%d\n",numRow); 
    return 0; 
} 

Merci pour vos réponses, je suis toujours en attente de la pomme d'or

Edit2: en utilisant les pointeurs de fichier de cstyle au lieu de C++ flux est beaucoup plus plus rapide. Donc je pense que c'est la voie à suivre.

Merci pour tous vos commentaires

+1

Enregistrement d'un fichier de 5 Go en mémoire est une mauvaise idée. Peut-être pourriez-vous expliquer pourquoi vous voulez faire cela, afin que nous puissions vous aider avec une meilleure façon de le faire. –

Répondre

5

gzip -cd compressed.gz | yourprogram

juste aller de l'avant et le lire ligne par ligne de stdin comme il est non compressé.

EDIT: Réponse à vos remarques sur les performances. Vous dites que la lecture ligne par ligne de STDIN est lente par rapport à la lecture directe d'un fichier non compressé. La différence réside dans les termes de mise en mémoire tampon. Normalement, le tube cédera à STDIN dès que la sortie sera disponible (non, ou très petit tampon là).Vous pouvez faire des «lectures de blocs tamponnés» à partir de STDIN et analyser les blocs de lecture vous-même pour gagner en performance. Vous pouvez obtenir le même résultat avec de meilleures performances en utilisant gzread(). (Lire un gros morceau, analyser le morceau, lire le morceau suivant, répéter)

+0

Juste à la deuxième ligne de sa question, il a écrit qu'il peut très bien lire le fichier ligne par ligne. –

+0

Lukas, avec la seule exception que cette solution ne nécessite pas un "fichier non compressé" existant. Il décompresse juste à la volée. –

+0

Ah, je suis désolé, j'ai mal lu ça. Je pensais qu'il savait lire le fichier compressé ligne par ligne. –

5

gzread ne lit que les morceaux du fichier, vous le bouclez comme vous le feriez avec un appel normal de read().

Avez-vous besoin de lire le fichier entier en mémoire? Si vous avez besoin de lire des lignes, vous devez lire un bloc important (disons 8192 octets) dans un tampon, parcourir ce tampon et trouver tous les caractères \ n 'et les traiter comme des lignes individuelles. Vous devez enregistrer la dernière partie en cas de partie de ligne, et ajoutez-la aux données que vous lirez la prochaine fois.

Vous pouvez également lire stdin et invoquer votre application comme

zcat bigfile.gz | ./yourprogram

Dans ce cas, vous pouvez utiliser fgets et similaires sur stdin. Ceci est également bénéfique dans la mesure où vous exécutez la décompression sur un processeur et le traitement des données sur un autre processeur :-)

+1

Le posix lu sur Linux est limité à 2.1gig, c'est même sur les plates-formes 64 bits. Je passe 3 jours à réaliser ce fait. – monkeyking

+0

Comme le dit notre numéro, vous pouvez simplement faire une lecture en continu des données compressées. Votre traitement de ligne lit à partir d'un décompresseur tamponné, qui lit des morceaux à la fois. Il n'y a pas besoin de lire des concerts à la fois, cela gaspille simplement de la mémoire. – gavinb

0

Je ne sais pas si cela sera une réponse à votre question, mais je crois que c'est plus qu'un commentaire:

Il y a quelques mois, j'ai découvert que le contenu de Wikipedia peut être téléchargé de la même manière que le fichier de données StackOverflow. Les deux décompressent en XML.

Je suis tombé sur une description de la façon dont le fichier de vidage compressé de plusieurs gigaoctets pouvait être analysé. Cela a été fait par des scripts Perl, mais la partie pertinente pour vous était que la compression Bzip2 était utilisée. Bzip2 est un schéma de compression de bloc, et le fichier compressé peut être divisé en éléments gérables, et chaque partie non compressée individuellement.

Malheureusement, je n'ai pas de lien à partager avec vous, et je ne peux pas suggérer comment vous le rechercheriez, sauf pour dire qu'il a été décrit sur une page Wikipedia 'dump de données' ou 'blog' .

EDIT: En fait, je ne ont un link

+0

Merci, je suppose que bzip2 est un outil de compression beaucoup mieux, mais tous les fichiers myinput sont. Gz, et je ne peux pas changer cela. – monkeyking

+0

D'accord, c'était juste une pensée, de toute façon. – pavium

Questions connexes