J'utilise une boucle for pour lire un fichier, mais je veux seulement lire des lignes spécifiques, disons les lignes # 26 et # 30. Existe-t-il une fonctionnalité intégrée pour y parvenir?
enumerate(x)utilise x.next, il n'a donc pas besoin de la totalité du fichier en mémoire.
Alok Singhal
3
Mon petit boeuf avec c'est que A) Vous voulez utiliser avec au lieu de la paire ouverte / fermée et donc garder le corps court, B) Mais le corps n'est pas si court. Cela ressemble à un compromis entre vitesse / espace et être Pythonic. Je ne sais pas quelle serait la meilleure solution.
Hamish Grubijan
5
avec est surfaite, python s'entend bien depuis plus de 13 ans sans lui
Dan D.
38
@Dan D. L'électricité est surfaite, l'humanité s'en est bien sortie pendant plus de 200 mille ans sans elle. ;-) 'avec' le rend plus sûr, plus lisible et plus court d'une ligne.
Romain Vincent
9
pourquoi utiliser pour boucle, je ne pense pas que vous compreniez le sens de big file. La boucle mettra des années à atteindre l'indice
Utilisez fileobject.readlines()ou for line in fileobjectcomme solution rapide pour les petits fichiers.
Utilisez linecachepour une solution plus élégante, qui sera assez rapide pour lire de nombreux fichiers, possible à plusieurs reprises.
Suivez les conseils de @ Alok et utilisez-leenumerate() pour les fichiers qui peuvent être très volumineux et qui ne rentrent pas en mémoire. Notez que l'utilisation de cette méthode peut ralentir car le fichier est lu séquentiellement.
Agréable. Je viens de regarder la source du linecachemodule et on dirait qu'il lit tout le fichier en mémoire. Donc, si l'accès aléatoire est plus important que l'optimisation de la taille, linecachec'est la meilleure méthode.
Alok Singhal
7
avec linecache.getlin ('some_file', 4) j'obtiens la 4ème ligne, pas la 5ème.
Juan
fait amusant: si vous utilisez un ensemble au lieu de la liste dans le deuxième exemple, vous obtenez le temps d'exécution O (1). Rechercher dans une liste est O (n). Les ensembles internes sont représentés comme des hachages, et c'est pourquoi vous obtenez le temps d'exécution O (1). pas un gros problème dans cet exemple, mais si vous utilisez une grande liste de nombres et que vous vous souciez de l'efficacité, les ensembles sont la voie à suivre.
rady
linecachesemble désormais fonctionner uniquement pour les fichiers source python
Paul H
Vous pouvez également utiliser linecache.getlines('/etc/passwd')[0:4]pour lire les première, deuxième, troisième et quatrième lignes.
zyy
30
Une approche rapide et compacte pourrait être:
def picklines(thefile, whatlines):return[x for i, x in enumerate(thefile)if i in whatlines]
cela accepte tout objet de type fichier ouvert thefile(laissant à l'appelant le soin de l'ouvrir à partir d'un fichier disque, ou via, par exemple, un socket ou un autre flux de type fichier) et un ensemble d'index de ligne de base zéro whatlines, et retourne un liste, avec une faible empreinte mémoire et une vitesse raisonnable. Si le nombre de lignes à renvoyer est énorme, vous préférerez peut-être un générateur:
def yieldlines(thefile, whatlines):return(x for i, x in enumerate(thefile)if i in whatlines)
ce qui n'est fondamentalement bon que pour boucler - notez que la seule différence vient de l'utilisation de parenthèses arrondies plutôt que carrées dans l' returninstruction, faisant une compréhension de liste et une expression de générateur respectivement.
Notez en outre que malgré la mention de "lignes" et de "fichier", ces fonctions sont beaucoup, beaucoup plus générales - elles fonctionneront sur n'importe quel itérable, que ce soit un fichier ouvert ou tout autre, renvoyant une liste (ou un générateur) d'éléments en fonction de leur numéro d'article progressif. Donc, je suggère d'utiliser des noms généraux plus appropriés ;-).
@ephemient, je ne suis pas d'accord - le genexp lit en douceur et parfaitement.
Alex Martelli
Excellente et élégante solution, merci! En effet, même les gros fichiers doivent être supportés, avec l'expression générateur. Impossible d'être plus élégant que ça, n'est-ce pas? :)
Samuel Lampa
Belle solution, comment cela se compare-t-il à celui proposé par @AdamMatan? La solution Adam pourrait être plus rapide car elle exploite des informations supplémentaires (les numéros de ligne augmentent de façon monotone) qui pourraient conduire à un arrêt précoce. J'ai un fichier de 10 Go que je ne peux pas charger en mémoire.
Mannaggia
2
@Mannaggia Ce n'est pas assez souligné dans cette réponse, mais whatlinesdevrait être un set, car if i in whatlinesil s'exécutera plus rapidement avec un ensemble plutôt qu'avec une liste (triée). Je ne l'ai pas remarqué en premier et j'ai plutôt conçu ma propre solution laide avec une liste triée (où je n'avais pas à numériser une liste à chaque fois, alors if i in whatlinesque c'est juste cela), mais la différence de performance était négligeable (avec mes données) et cela la solution est beaucoup plus élégante.
Cela lit le fichier entier en mémoire. Vous pourriez aussi bien appeler file.read (). Split ('\ n') puis utiliser les recherches d'index de tableau pour obtenir la ligne d'intérêt ...
tranche Un objet contenant généralement une partie d'une séquence. Une tranche est créée en utilisant la notation en indice, [] avec des deux-points entre les nombres lorsque plusieurs sont donnés, comme dans variable_name [1: 3: 5]. La notation crochet (indice) utilise des objets slice en interne (ou dans les anciennes versions, __getslice __ () et __setslice __ ()).
Bien que la notation de tranche ne soit pas directement applicable aux itérateurs en général, le itertoolspackage contient une fonction de remplacement:
from itertools import islice
# print the 100th linewith open('the_file')as lines:for line in islice(lines,99,100):print line
# print each third line until 100with open('the_file')as lines:for line in islice(lines,0,100,3):print line
L'avantage supplémentaire de la fonction est qu'elle ne lit l'itérateur qu'à la fin. Vous pouvez donc faire des choses plus complexes:
with open('the_file')as lines:# print the first 100 linesfor line in islice(lines,100):print line
# then skip the next 5for line in islice(lines,5):pass# print the restfor line in lines:print line
Et pour répondre à la question d'origine:
# how to read lines #26 and #30In[365]: list(islice(xrange(1,100),25,30,4))Out[365]:[26,30]
De loin la meilleure approche lorsque vous travaillez avec des fichiers volumineux. Mon programme est passé de 8 Go + à presque rien. Le compromis était l'utilisation du processeur qui est passée de ~ 15% à ~ 40% mais le traitement réel du fichier était 70% plus rapide. Je ferai ce compromis toute la journée. Merci! 🎉🎉🎉
GollyJer
1
Cela me semble le plus pythonique. Merci!
ipetrik
10
La lecture de fichiers est incroyablement rapide. La lecture d'un fichier de 100 Mo prend moins de 0,1 seconde (voir mon article Lecture et écriture de fichiers avec Python ). Par conséquent, vous devez le lire complètement, puis travailler avec les lignes simples.
Ce que la plupart des réponses font ici n'est pas mauvais, mais un mauvais style. L'ouverture des fichiers doit toujours se faire withcar elle garantit que le fichier est refermé.
Vous devez donc le faire comme ceci:
with open("path/to/file.txt")as f:
lines = f.readlines()print(lines[26])# or whatever you want to do with this lineprint(lines[30])# or whatever you want to do with this line
D'énormes fichiers
Si vous avez un fichier volumineux et que la consommation de mémoire est un problème, vous pouvez le traiter ligne par ligne:
with open("path/to/file.txt")as f:for i, line in enumerate(f):pass# process line i
IMO c'est un très mauvais style de lire un fichier entier de longueur inconnue, juste pour obtenir les 30 premières lignes .. qu'en est-il de la consommation de mémoire .. et qu'en est-il des flux sans fin?
return42
@ return42 Cela dépend beaucoup de l'application. Pour beaucoup, il est tout à fait correct de supposer qu'un fichier texte a une taille bien inférieure à la mémoire disponible. S'il vous arrive d'avoir des fichiers potentiellement volumineux, j'ai modifié ma réponse.
Martin Thoma
merci pour votre ajout, qui est le même que la réponse alok . Et désolé non, je ne pense pas que cela dépende de l'application. OMI, il est toujours préférable de ne pas lire plus de lignes que nécessaire.
return42
7
Certains d'entre eux sont charmants, mais cela peut être fait beaucoup plus simplement:
start =0# some starting index
end =5000# some ending index
filename ='test.txt'# some file we want to usewith open(filename)as fh:
data = fin.readlines()[start:end]print(data)
Cela utilisera simplement le découpage de liste, il charge tout le fichier, mais la plupart des systèmes minimisent l'utilisation de la mémoire de manière appropriée, c'est plus rapide que la plupart des méthodes indiquées ci-dessus et fonctionne sur mes fichiers de données 10G +. Bonne chance!
Vous pouvez faire un appel à la fonction de recherche () qui positionne votre tête de lecture sur un octet spécifié dans le fichier. Cela ne vous sera utile que si vous savez exactement combien d'octets (caractères) sont écrits dans le fichier avant la ligne que vous souhaitez lire. Peut-être que votre fichier est strictement formaté (chaque ligne est un nombre X d'octets?) Ou, vous pouvez compter le nombre de caractères vous-même (n'oubliez pas d'inclure des caractères invisibles comme les sauts de ligne) si vous voulez vraiment augmenter la vitesse.
Sinon, vous devez lire chaque ligne avant la ligne souhaitée, conformément à l'une des nombreuses solutions déjà proposées ici.
Si votre gros fichier texte fileest strictement bien structuré (ce qui signifie que chaque ligne a la même longueur l), vous pouvez utiliser la nligne -th
with open(file)as f:
f.seek(n*l)
line = f.readline()
last_pos = f.tell()
Avis de non-responsabilité Cela ne fonctionne que pour les fichiers de même longueur!
C'est vrai, c'est moins efficace que celui d'Alok, mais le mien utilise une déclaration with;)
Hamish Grubijan
2
Si cela ne vous dérange pas d'importer, fileinput fait exactement ce dont vous avez besoin (c'est-à-dire que vous pouvez lire le numéro de ligne de la ligne actuelle)
def getitems(iterable, items):
items = list(items)# get a list from any iterable and make our own copy# since we modify itif items:
items.sort()for n, v in enumerate(iterable):if n == items[0]:yield v
items.pop(0)ifnot items:breakprint list(getitems(open("/usr/share/dict/words"),[25,29]))# ['Abelson\n', 'Abernathy\n']# note that index 25 is the 26th item
Roger, mon gars préféré! Cela pourrait bénéficier d'une déclaration with.
Hamish Grubijan
2
Je préfère cette approche car elle est plus polyvalente, c'est-à-dire que vous pouvez l'utiliser sur un fichier, sur le résultat de f.readlines(), sur un StringIOobjet, peu importe:
def read_specific_lines(file, lines_to_read):"""file is any iterable; lines_to_read is an iterable containing int values"""
lines = set(lines_to_read)
last = max(lines)for n, line in enumerate(file):if n +1in lines:yield line
if n +1> last:return>>>with open(r'c:\temp\words.txt')as f:[s for s in read_specific_lines(f,[1,2,3,1000])]['A\n','a\n','aa\n','accordant\n']
def indexLines(filename, lines=[2,4,6,8,10,12,3,5,7,1]):
fp = open(filename,"r")
src = fp.readlines()
data =[(index, line)for index, line in enumerate(src)if index in lines]
fp.close()return data
# Usage below
filename ="C:\\Your\\Path\\And\\Filename.txt"for line in indexLines(filename):# using default list, specify your own list of lines otherwiseprint"Line: %s\nData: %s\n"%(line[0], line[1])
Les objets fichier ont une méthode .readlines () qui vous donnera une liste du contenu du fichier, une ligne par élément de liste. Après cela, vous pouvez simplement utiliser des techniques de découpage de liste normales.
ce n'est pas une réponse valable. après le premier appel à readlines()l'itérateur sera épuisé et le deuxième appel renverra une liste vide ou lancera une erreur (je ne me souviens plus de laquelle)
Paul H
1
Vous pouvez le faire très simplement avec cette syntaxe que quelqu'un a déjà mentionnée, mais c'est de loin la façon la plus simple de le faire:
Pour imprimer certaines lignes dans un fichier texte. Créez une liste "lines2print" puis imprimez simplement lorsque l'énumération est "dans" la liste lines2print. Pour se débarrasser des '\ n' supplémentaires, utilisez line.strip () ou line.strip ('\ n'). J'aime juste la "compréhension de liste" et j'essaye d'utiliser quand je peux. J'aime la méthode "avec" pour lire les fichiers texte afin d'éviter de laisser un fichier ouvert pour une raison quelconque.
lines2print =[26,30]# can be a big list and order doesn't matter.with open("filepath",'r')as fp:[print(x.strip())for ei,x in enumerate(fp)if ei in lines2print]
ou si la liste est petite, tapez simplement list comme liste dans la compréhension.
with open("filepath",'r')as fp:[print(x.strip())for ei,x in enumerate(fp)if ei in[26,30]]
Pour imprimer la ligne souhaitée. Pour imprimer la ligne au-dessus / en dessous de la ligne requise.
def dline(file,no,add_sub=0):
tf=open(file)for sno,line in enumerate(tf):if sno==no-1+add_sub:print(line)
tf.close()
exécuter ----> dline ("D: \ dummy.txt", 6) ie dline ("file path", line_number, si vous voulez que la ligne supérieure de la ligne recherchée donne 1 pour -1 inférieur c'est la valeur par défaut optionnelle sera être pris 0)
Si vous souhaitez lire des lignes spécifiques, telles que la ligne commençant après une ligne de seuil, vous pouvez utiliser les codes suivants,
file = open("files.txt","r")
lines = file.readlines() ## convert to list of lines
datas = lines[11:] ## raed the specific lines
Donne le mauvais résultat, car vous ne pouvez pas utiliser des lignes de lecture et des lignes de lecture comme ça (elles modifient chacune la position de lecture actuelle).
Je suis désolé d'avoir négligé une énorme erreur dans mon premier code. L'erreur a été corrigée et le code actuel devrait fonctionner comme prévu. Merci d'avoir signalé mon erreur, Roger Pate.
Réponses:
Si le fichier à lire est volumineux et que vous ne souhaitez pas lire l'intégralité du fichier en mémoire à la fois:
Notez que
i == n-1
pour lan
e ligne.En Python 2.6 ou version ultérieure:
la source
enumerate(x)
utilisex.next
, il n'a donc pas besoin de la totalité du fichier en mémoire.big file
. La boucle mettra des années à atteindre l'indiceLa réponse rapide:
ou:
Il existe une solution plus élégante pour extraire de nombreuses lignes: linecache (gracieuseté de "python: comment passer à une ligne particulière dans un énorme fichier texte?" , Une précédente question stackoverflow.com).
Citant la documentation python liée ci-dessus:
Remplacez le
4
par le numéro de ligne souhaité, et c'est parti. Notez que 4 apporterait la cinquième ligne car le compte est basé sur zéro.Si le fichier peut être très volumineux et causer des problèmes lors de la lecture en mémoire, il peut être judicieux de suivre les conseils de @ Alok et d'utiliser enumerate () .
De conclure:
fileobject.readlines()
oufor line in fileobject
comme solution rapide pour les petits fichiers.linecache
pour une solution plus élégante, qui sera assez rapide pour lire de nombreux fichiers, possible à plusieurs reprises.enumerate()
pour les fichiers qui peuvent être très volumineux et qui ne rentrent pas en mémoire. Notez que l'utilisation de cette méthode peut ralentir car le fichier est lu séquentiellement.la source
linecache
module et on dirait qu'il lit tout le fichier en mémoire. Donc, si l'accès aléatoire est plus important que l'optimisation de la taille,linecache
c'est la meilleure méthode.linecache
semble désormais fonctionner uniquement pour les fichiers source pythonlinecache.getlines('/etc/passwd')[0:4]
pour lire les première, deuxième, troisième et quatrième lignes.Une approche rapide et compacte pourrait être:
cela accepte tout objet de type fichier ouvert
thefile
(laissant à l'appelant le soin de l'ouvrir à partir d'un fichier disque, ou via, par exemple, un socket ou un autre flux de type fichier) et un ensemble d'index de ligne de base zérowhatlines
, et retourne un liste, avec une faible empreinte mémoire et une vitesse raisonnable. Si le nombre de lignes à renvoyer est énorme, vous préférerez peut-être un générateur:ce qui n'est fondamentalement bon que pour boucler - notez que la seule différence vient de l'utilisation de parenthèses arrondies plutôt que carrées dans l'
return
instruction, faisant une compréhension de liste et une expression de générateur respectivement.Notez en outre que malgré la mention de "lignes" et de "fichier", ces fonctions sont beaucoup, beaucoup plus générales - elles fonctionneront sur n'importe quel itérable, que ce soit un fichier ouvert ou tout autre, renvoyant une liste (ou un générateur) d'éléments en fonction de leur numéro d'article progressif. Donc, je suggère d'utiliser des noms généraux plus appropriés ;-).
la source
whatlines
devrait être unset
, carif i in whatlines
il s'exécutera plus rapidement avec un ensemble plutôt qu'avec une liste (triée). Je ne l'ai pas remarqué en premier et j'ai plutôt conçu ma propre solution laide avec une liste triée (où je n'avais pas à numériser une liste à chaque fois, alorsif i in whatlines
que c'est juste cela), mais la différence de performance était négligeable (avec mes données) et cela la solution est beaucoup plus élégante.Pour offrir une autre solution:
J'espère que c'est rapide et facile :)
la source
si vous voulez la ligne 7
la source
close()
le fichier lorsque vous l'ouvrez de cette façon?Par souci d'exhaustivité, voici une autre option.
Commençons par une définition à partir des documents python :
Bien que la notation de tranche ne soit pas directement applicable aux itérateurs en général, le
itertools
package contient une fonction de remplacement:L'avantage supplémentaire de la fonction est qu'elle ne lit l'itérateur qu'à la fin. Vous pouvez donc faire des choses plus complexes:
Et pour répondre à la question d'origine:
la source
La lecture de fichiers est incroyablement rapide. La lecture d'un fichier de 100 Mo prend moins de 0,1 seconde (voir mon article Lecture et écriture de fichiers avec Python ). Par conséquent, vous devez le lire complètement, puis travailler avec les lignes simples.
Ce que la plupart des réponses font ici n'est pas mauvais, mais un mauvais style. L'ouverture des fichiers doit toujours se faire
with
car elle garantit que le fichier est refermé.Vous devez donc le faire comme ceci:
D'énormes fichiers
Si vous avez un fichier volumineux et que la consommation de mémoire est un problème, vous pouvez le traiter ligne par ligne:
la source
Certains d'entre eux sont charmants, mais cela peut être fait beaucoup plus simplement:
Cela utilisera simplement le découpage de liste, il charge tout le fichier, mais la plupart des systèmes minimisent l'utilisation de la mémoire de manière appropriée, c'est plus rapide que la plupart des méthodes indiquées ci-dessus et fonctionne sur mes fichiers de données 10G +. Bonne chance!
la source
Vous pouvez faire un appel à la fonction de recherche () qui positionne votre tête de lecture sur un octet spécifié dans le fichier. Cela ne vous sera utile que si vous savez exactement combien d'octets (caractères) sont écrits dans le fichier avant la ligne que vous souhaitez lire. Peut-être que votre fichier est strictement formaté (chaque ligne est un nombre X d'octets?) Ou, vous pouvez compter le nombre de caractères vous-même (n'oubliez pas d'inclure des caractères invisibles comme les sauts de ligne) si vous voulez vraiment augmenter la vitesse.
Sinon, vous devez lire chaque ligne avant la ligne souhaitée, conformément à l'une des nombreuses solutions déjà proposées ici.
la source
Si votre gros fichier texte
file
est strictement bien structuré (ce qui signifie que chaque ligne a la même longueurl
), vous pouvez utiliser lan
ligne -thAvis de non-responsabilité Cela ne fonctionne que pour les fichiers de même longueur!
la source
Que dis-tu de ça:
la source
Si cela ne vous dérange pas d'importer, fileinput fait exactement ce dont vous avez besoin (c'est-à-dire que vous pouvez lire le numéro de ligne de la ligne actuelle)
la source
la source
Je préfère cette approche car elle est plus polyvalente, c'est-à-dire que vous pouvez l'utiliser sur un fichier, sur le résultat de
f.readlines()
, sur unStringIO
objet, peu importe:la source
Voici mon petit 2 cents, pour ce que ça vaut;)
la source
Un changement meilleur et mineur pour la réponse d'Alok Singhal
la source
Les objets fichier ont une méthode .readlines () qui vous donnera une liste du contenu du fichier, une ligne par élément de liste. Après cela, vous pouvez simplement utiliser des techniques de découpage de liste normales.
http://docs.python.org/library/stdtypes.html#file.readlines
la source
@OP, vous pouvez utiliser énumérer
la source
À l'aide de l'instruction with, cela ouvre le fichier, imprime les lignes 26 et 30, puis ferme le fichier. Facile!
la source
readlines()
l'itérateur sera épuisé et le deuxième appel renverra une liste vide ou lancera une erreur (je ne me souviens plus de laquelle)Vous pouvez le faire très simplement avec cette syntaxe que quelqu'un a déjà mentionnée, mais c'est de loin la façon la plus simple de le faire:
la source
Pour imprimer la ligne n ° 3,
Auteur original: Frank Hofmann
la source
Assez rapide et au point.
Pour imprimer certaines lignes dans un fichier texte. Créez une liste "lines2print" puis imprimez simplement lorsque l'énumération est "dans" la liste lines2print. Pour se débarrasser des '\ n' supplémentaires, utilisez line.strip () ou line.strip ('\ n'). J'aime juste la "compréhension de liste" et j'essaye d'utiliser quand je peux. J'aime la méthode "avec" pour lire les fichiers texte afin d'éviter de laisser un fichier ouvert pour une raison quelconque.
ou si la liste est petite, tapez simplement list comme liste dans la compréhension.
la source
Pour imprimer la ligne souhaitée. Pour imprimer la ligne au-dessus / en dessous de la ligne requise.
exécuter ----> dline ("D: \ dummy.txt", 6) ie dline ("file path", line_number, si vous voulez que la ligne supérieure de la ligne recherchée donne 1 pour -1 inférieur c'est la valeur par défaut optionnelle sera être pris 0)
la source
Si vous souhaitez lire des lignes spécifiques, telles que la ligne commençant après une ligne de seuil, vous pouvez utiliser les codes suivants,
file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines
la source
la source
Je pense que cela fonctionnerait
la source