Est-il facile de lire une ligne d'un fichier texte compressé en gz en utilisant python sans extraire le fichier complètement ? J'ai un fichier text.gz qui fait environ 200 mb. Lorsque je l'extrais, il devient 7,4 Go. Et ce n'est pas le seul fichier que je dois lire. Pour l'ensemble du processus, je dois lire 10 fichiers. Bien que ce soit un travail séquentiel, je pense qu'il serait judicieux de le faire sans extraire toute l'information. Je ne sais même pas si c'est possible. Comment peut-on le faire en utilisant Python ? J'ai besoin de lire un fichier texte ligne par ligne.
Réponses
Trop de publicités?Utilisation de gzip.GzipFile :
import gzip
with gzip.open('input.gz','rt') as f:
for line in f:
print('got line', line)
Note : gzip.open(filename, mode)
est un alias pour gzip.GzipFile(filename, mode)
. Je préfère le premier, car il ressemble à with open(...) as f:
utilisé pour l'ouverture de fichiers non compressés.
Vous pouvez utiliser le module gzip standard de python. Il suffit d'utiliser :
gzip.open('myfile.gz')
pour ouvrir le fichier comme n'importe quel autre fichier et lire ses lignes.
Plus d'informations ici : Module gzip Python
Avez-vous essayé d'utiliser gzip.GzipFile ? Les arguments sont similaires à open
.
La bibliothèque gzip utilise (évidemment) gzip
ce qui peut être un peu lent. Vous pouvez accélérer les choses avec un appel système à pigz la version parallélisée de gzip
. Les inconvénients sont que vous devez installer pigz
et il prendra plus de cœurs pendant l'exécution, mais il est beaucoup plus rapide et ne nécessite pas plus de mémoire. L'appel au fichier devient alors os.popen('pigz -dc ' + filename)
au lieu de gzip.open(filename,'rt')
. Les drapeaux pigz sont -d
pour la décompression et -c
pour une sortie stdout qui peut ensuite être saisie par os.popen
.
Le code suivant prend un fichier et un numéro (1 ou 2) et compte le nombre de lignes dans le fichier avec les différents appels tout en mesurant le temps que prend le code. En définissant le code suivant dans le fichier unzip-file.py
:
#!/usr/bin/python
import os
import sys
import time
import gzip
def local_unzip(obj):
t0 = time.time()
count = 0
with obj as f:
for line in f:
count += 1
print(time.time() - t0, count)
r = sys.argv[1]
if sys.argv[2] == "1":
local_unzip(gzip.open(r,'rt'))
else:
local_unzip(os.popen('pigz -dc ' + r))
Appeler ces derniers en utilisant /usr/bin/time -f %M
qui mesure l'utilisation maximale de la mémoire du processus sur un fichier de 28G que nous obtenons :
$ /usr/bin/time -f %M ./unzip-file.py $file 1
(3037.2604110240936, 1223422024)
5116
$ /usr/bin/time -f %M ./unzip-file.py $file 2
(598.771901845932, 1223422024)
4996
On constate que l'appel système est environ cinq fois plus rapide (10 minutes contre 50 minutes) en utilisant pratiquement la même mémoire maximale. Il est également intéressant de noter que, selon ce que vous faites, la lecture par ligne dans le fichier peut ne pas être le facteur limitant, auquel cas l'option que vous prenez n'a pas d'importance.