web-dev-qa-db-fra.com

Lecture de lignes spécifiques uniquement

J'utilise une boucle for pour lire un fichier, mais je veux seulement lire des lignes spécifiques, par exemple les lignes 26 et 30. Existe-t-il une fonctionnalité intégrée pour y parvenir?

Merci

161
3zzy

Si le fichier à lire est volumineux et que vous ne voulez pas lire tout le fichier en mémoire à la fois:

fp = open("file")
for i, line in enumerate(fp):
    if i == 25:
        # 26th line
    Elif i == 29:
        # 30th line
    Elif i > 29:
        break
fp.close()

Notez que i == n-1 pour la nth ligne.


En Python 2.6 ou version ultérieure:

with open("file") as fp:
    for i, line in enumerate(fp):
        if i == 25:
            # 26th line
        Elif i == 29:
            # 30th line
        Elif i > 29:
            break
213
Alok Singhal

La réponse rapide:

f=open('filename')
lines=f.readlines()
print lines[25]
print lines[29]

ou:

lines=[25, 29]
i=0
f=open('filename')
for line in f:
    if i in lines:
        print i
    i+=1

Il existe une solution plus élégante pour extraire de nombreuses lignes: linecache (avec la permission de "python: comment passer à une ligne particulière dans un fichier texte énorme?" , une question précédente de stackoverflow.com).

Citant la documentation python liée ci-dessus:

>>> import linecache
>>> linecache.getline('/etc/passwd', 4)
'sys:x:3:3:sys:/dev:/bin/sh\n'

Remplacez le 4 par le numéro de ligne souhaité et le tour est joué. Notez que 4 amènerait la cinquième ligne car le compte est basé sur zéro.

Si le fichier est volumineux et pose des problèmes de lecture, il peut être judicieux de suivre les conseils de @ Alok et d'utiliser enumerate () .

De conclure:

  • Utilisez fileobject.readlines() ou for line in fileobject comme solution rapide pour les petits fichiers. 
  • Utilisez linecache pour une solution plus élégante, qui sera assez rapide pour lire de nombreux fichiers, possible plusieurs fois.
  • Suivez les conseils de @ Alok et utilisez enumerate() pour les fichiers pouvant être volumineux et ne pas tenir dans la mémoire. Notez que l'utilisation de cette méthode peut être ralentie car le fichier est lu séquentiellement.
129
Adam Matan

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 ressemblant à un fichier ouvert thefile (laissant à l'appelant le choix d'ouvrir ou non à partir d'un fichier disque, ou via un socket, ou tout autre flux de type fichier) et un ensemble d'index de ligne de base zéro whatlines, et renvoie une liste, avec une faible empreinte mémoire et une vitesse raisonnable. Si le nombre de lignes à renvoyer est énorme, vous pouvez préférer un générateur:

def yieldlines(thefile, whatlines):
  return (x for i, x in enumerate(thefile) if i in whatlines)

notez que la seule différence provient de l’utilisation de parenthèses arrondies plutôt que carrées dans l’instruction return, permettant ainsi une compréhension de la liste et une expression génératrice.

Notez en outre que, malgré la mention des "lignes" et du "fichier", ces fonctions sont très nombreuses, beaucoup plus général - elles fonctionneront sur toutes -, ce sera un fichier ouvert ou autre, retournant une liste (ou un générateur) d’articles en fonction de leur numéro d’article progressif. Donc, je suggérerais d'utiliser des noms généraux plus appropriés ;-).

25
Alex Martelli

Pour proposer une autre solution:

import linecache
linecache.getline('Sample.txt', Number_of_Line)

J'espère que c'est rapide et facile :)

25
KingMak

si vous voulez la ligne 7

 line = open ("fichier.txt", "r"). readlines () [7] 
12
MadSc13ntist

Par souci d'exhaustivité, voici une autre option.

Commençons par une définition de python docs :

slice Un objet contenant généralement une partie d'une séquence. Une tranche est créée à l'aide de la notation en indice, [] avec des points entre deux chiffres lorsque plusieurs sont indiqués, comme dans nom_variable [1: 3: 5]. La notation crochet (indice) utilise les objets slice en interne (ou dans les versions antérieures, __getslice __ () et __setslice __ ()).

Bien que la notation de tranche ne soit pas directement applicable aux itérateurs, le paquetage itertools contient une fonction de remplacement:

from itertools import islice

# print the 100th line
with open('the_file') as lines:
    for line in islice(lines, 99, 100):
        print line

# print each third line until 100
with 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 pas l'itérateur jusqu'à la fin. Vous pouvez donc faire des choses plus complexes:

with open('the_file') as lines:
    # print the first 100 lines
    for line in islice(lines, 100):
        print line

    # then skip the next 5
    for line in islice(lines, 5):
        pass

    # print the rest
    for line in lines:
        print line

Et pour répondre à la question initiale:

# how to read lines #26 and #30
In [365]: list(islice(xrange(1,100), 25, 30, 4))
Out[365]: [26, 30]
9
newtover

Lire des 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 devriez le lire complètement et ensuite travailler avec les lignes simples.

Ce que la plupart des gens répondent ici n’est pas mauvais, mais mauvais style L’ouverture des fichiers doit toujours se faire avec with car cela permet de s’assurer que le fichier est refermé.

Donc, vous devriez 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 line
print(lines[30])  # or whatever you want to do with this line

Énormes fichiers

Si vous avez beaucoup de fichiers 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
5
Martin Thoma

Certaines d'entre elles sont belles, 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 use

with open(filename) as fh:
    data = fin.readlines()[start:end]

print(data)

Cela utilisera simplement le découpage de liste, il chargera le fichier entier, mais la plupart des systèmes minimiseront l'utilisation de la mémoire de manière appropriée, il est plus rapide que la plupart des méthodes indiquées ci-dessus et fonctionne sur mes fichiers de données 10G +. Bonne chance!

4
Will

Vous pouvez faire un appel seek () qui positionne votre tête de lecture sur un octet spécifié du fichier. Cela ne vous aidera pas si vous ne savez pas exactement combien d'octets (caractères) sont écrits dans le fichier avant la ligne que vous voulez lire. Peut-être que votre fichier est strictement formaté (chaque ligne correspond à un nombre X d'octets?) Ou vous pouvez compter vous-même le nombre de caractères (n'oubliez pas d'inclure des caractères invisibles comme des 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.

3
Roman

Que dis-tu de ça:

>>> with open('a', 'r') as fin: lines = fin.readlines()
>>> for i, line in enumerate(lines):
      if i > 30: break
      if i == 26: dox()
      if i == 30: doy()
2
Hamish Grubijan

Un changement meilleur et mineur pour la réponse d'Alok Singhal

fp = open("file")
for i, line in enumerate(fp,1):
    if i == 26:
        # 26th line
    Elif i == 30:
        # 30th line
    Elif i > 30:
        break
fp.close()
2
sedic

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 objet StringIO, 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 + 1 in 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']
2
Robert Rossney

Si cela ne vous dérange pas d’importer alors fileinput fait exactement ce dont vous avez besoin (c’est vous pouvez lire le numéro de la ligne courante)

2
ennuikiller
def getitems(iterable, items):
  items = list(items) # get a list from any iterable and make our own copy
                      # since we modify it
  if items:
    items.sort()
    for n, v in enumerate(iterable):
      if n == items[0]:
        yield v
        items.pop(0)
        if not items:
          break

print list(getitems(open("/usr/share/dict/words"), [25, 29]))
# ['Abelson\n', 'Abernathy\n']
# note that index 25 is the 26th item
2
Roger Pate

Voici mes 2 centimes, pour ce que ça vaut;)

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 otherwise
    print "Line: %s\nData: %s\n" % (line[0], line[1])
2
AWainb
file = '/path/to/file_to_be_read.txt'
with open(file) as f:
    print f.readlines()[26]
    print f.readlines()[30]

En utilisant l'instruction with, cela ouvre le fichier, imprime les lignes 26 et 30, puis ferme le fichier. Simple!

1
user3901273

Les objets de fichier ont une méthode .readlines () qui vous donnera une liste du contenu du fichier, une ligne par élément de la liste. Après cela, vous pouvez simplement utiliser les techniques de découpage de liste normales.

http://docs.python.org/library/stdtypes.html#file.readlines

1
Josh Wright

Vous pouvez le faire très simplement avec cette syntaxe déjà mentionnée par quelqu'un, mais c'est de loin le moyen le plus simple de le faire:

inputFile = open("lineNumbers.txt", "r")
lines = inputFile.readlines()
print (lines[0])
print (lines[2])
1
Trey50Daniel

Pour imprimer la ligne n ° 3, 

line_number = 3

with open(filename,"r") as file:
current_line = 1
for line in file:
    if current_line == line_number:
        print(file.readline())
        break
    current_line += 1

Auteur original: Frank Hofmann

1
crazy_daffodils

@OP, vous pouvez utiliser énumérer

for n,line in enumerate(open("file")):
    if n+1 in [26,30]: # or n in [25,29] 
       print line.rstrip()
1
ghostdog74

Si votre fichier texte volumineux file est strictement bien structuré (chaque ligne a la même longueur l), vous pouvez utiliser pour n- ème ligne

with open(file) as f:
    f.seek(n*l)
    line = f.readline()  # please notice the s at the end!
    last_pos = f.tell()

Avertissement Ceci ne fonctionne que pour les fichiers de la même longueur!

1
Michael Dorner

Pour imprimer la ligne désirée .. Pour imprimer la ligne située au-dessus/au-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()

execute ----> dline ("D:\dummy.txt", 6) c'est-à-dire dline ("chemin du fichier", numéro_ligne, si vous voulez que la ligne supérieure de la ligne recherchée donne 1 pour inférieur -1, il s'agit d'une valeur par défaut facultative être pris 0)

0
sudhir tataraju

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 vous débarrasser des '\ n' supplémentaires, utilisez line.strip () ou line.strip ('\ n ') . J'aime juste "comprendre la liste" et essayer d'utiliser quand je peux . J'aime la méthode "avec" pour lire les fichiers texte afin d'empêcher 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, il suffit de taper la liste 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]]
0
Mike Adrion