Lire les N premières lignes d'un fichier en python

150

Nous avons un gros fichier de données brutes que nous aimerions découper à une taille spécifiée. J'ai de l'expérience en .net c #, mais j'aimerais le faire en python pour simplifier les choses et par intérêt.

Comment procéder pour obtenir les N premières lignes d'un fichier texte en python? Le système d'exploitation utilisé aura-t-il un effet sur l'implémentation?

Russell
la source
Puis-

Réponses:

241

Python 2

with open("datafile") as myfile:
    head = [next(myfile) for x in xrange(N)]
print head

Python 3

with open("datafile") as myfile:
    head = [next(myfile) for x in range(N)]
print(head)

Voici une autre façon (à la fois Python 2 et 3)

from itertools import islice
with open("datafile") as myfile:
    head = list(islice(myfile, N))
print head
John La Rooy
la source
1
Merci, c'est vraiment très utile. Quelle est la différence entre les deux? (en termes de performances, de bibliothèques requises, de compatibilité, etc.)?
Russell
1
Je m'attends à ce que les performances soient similaires, peut-être la première à être légèrement plus rapide. Mais le premier ne fonctionnera pas si le fichier n'a pas au moins N lignes. Il est préférable de mesurer les performances par rapport à certaines données typiques avec lesquelles vous les utiliserez.
John La Rooy
1
L'instruction with fonctionne sur Python 2.6 et nécessite une instruction d'importation supplémentaire sur 2.5. Pour la version 2.4 ou antérieure, vous devez réécrire le code avec un essai ... sauf bloc. Stylistiquement, je préfère la première option, bien que, comme mentionné, la seconde soit plus robuste pour les fichiers courts.
Alasdair
1
islice est probablement plus rapide car il est implémenté dans C.
Alice Purcell
22
Gardez à l'esprit que si les fichiers ont moins de N lignes, cela soulèvera une exception StopIteration que vous devez gérer
Ilian Iliev
19
N = 10
with open("file.txt", "a") as file:  # the a opens it in append mode
    for i in range(N):
        line = next(file).strip()
        print(line)
ghostdog74
la source
23
Je grince des dents à chaque fois que je vois f = open("file")sans exception la manipulation pour fermer le dossier. La manière pythonique de gérer les fichiers est avec un gestionnaire de contexte, c'est-à-dire en utilisant l'instruction with. Ceci est couvert dans le didacticiel Python d'entrée-sortie . "It is good practice to use the with keyword when dealing with file objects. This has the advantage that the file is properly closed after its suite finishes, even if an exception is raised on the way."
Mark Mikofski
1
Pourquoi ouvrir le fichier en mode ajout?
AMC
13

Si vous voulez lire les premières lignes rapidement et que vous ne vous souciez pas des performances, vous pouvez utiliser .readlines()quel objet de liste renvoie, puis découper la liste.

Par exemple pour les 5 premières lignes:

with open("pathofmyfileandfileandname") as myfile:
    firstNlines=myfile.readlines()[0:5] #put here the interval you want

Remarque: le fichier entier est lu, ce n'est donc pas le meilleur du point de vue des performances, mais il est facile à utiliser, rapide à écrire et facile à retenir, donc si vous voulez simplement effectuer un calcul ponctuel, c'est très pratique

print firstNlines

Un avantage par rapport aux autres réponses est la possibilité de sélectionner facilement la plage de lignes, par exemple en sautant les 10 premières lignes [10:30]ou les 10 dernières [:-10]ou en ne prenant que des lignes paires [::2].

GM
la source
2
La meilleure réponse est probablement beaucoup plus efficace, mais celle-ci fonctionne comme un charme pour les petits fichiers.
T.Chmelevskij
2
Notez que cela lit en fait tout le fichier dans une liste en premier (myfile.readlines ()), puis joint les 5 premières lignes de celui-ci.
AbdealiJK
2
Cela devrait être évité.
anilbey
1
Je ne vois aucune raison d'utiliser cela, ce n'est pas plus simple que les solutions beaucoup plus efficaces.
AMC
@AMC merci pour les commentaires, je l'utilise dans la console pour explorer les données lorsque je dois jeter un coup d'œil rapide aux premières lignes, cela me fait gagner du temps dans l'écriture du code.
GM
9

Ce que je fais, c'est appeler les N lignes en utilisant pandas. Je pense que les performances ne sont pas les meilleures, mais par exemple si N=1000:

import pandas as pd
yourfile = pd.read('path/to/your/file.csv',nrows=1000)
Cro-Magnon
la source
3
Mieux vaut utiliser l' nrowsoption, qui peut être définie sur 1000 et le fichier entier n'est pas chargé. pandas.pydata.org/pandas-docs/stable/generated/… En général, pandas a ceci et d'autres techniques d'économie de mémoire pour les gros fichiers.
philshem
Oui, tu as raison. Je viens de le corriger. Désolé pour l'erreur.
Cro-Magnon
1
Vous pouvez également ajouter seppour définir un délimiteur de colonne (qui ne devrait pas se produire dans un fichier non-csv)
philshem
1
@ Cro-Magnon Je ne trouve pas la pandas.read()fonction dans la documentation, connaissez-vous des informations sur le sujet?
AMC
6

Il n'y a pas de méthode spécifique pour lire le nombre de lignes exposées par l'objet fichier.

Je suppose que le moyen le plus simple serait de suivre:

lines =[]
with open(file_name) as f:
    lines.extend(f.readline() for i in xrange(N))
artdanil
la source
C'est quelque chose que j'avais réellement prévu. Cependant, j'ai pensé à ajouter chaque ligne à la liste. Je vous remercie.
artdanil
4

Basé sur la réponse la plus votée de gnibbler (20 novembre 09 à 0:27): cette classe ajoute la méthode head () et tail () au fichier object.

class File(file):
    def head(self, lines_2find=1):
        self.seek(0)                            #Rewind file
        return [self.next() for x in xrange(lines_2find)]

    def tail(self, lines_2find=1):  
        self.seek(0, 2)                         #go to end of file
        bytes_in_file = self.tell()             
        lines_found, total_bytes_scanned = 0, 0
        while (lines_2find+1 > lines_found and
               bytes_in_file > total_bytes_scanned): 
            byte_block = min(1024, bytes_in_file-total_bytes_scanned)
            self.seek(-(byte_block+total_bytes_scanned), 2)
            total_bytes_scanned += byte_block
            lines_found += self.read(1024).count('\n')
        self.seek(-total_bytes_scanned, 2)
        line_list = list(self.readlines())
        return line_list[-lines_2find:]

Usage:

f = File('path/to/file', 'r')
f.head(3)
f.tail(3)
fdb
la source
4

Les deux façons les plus intuitives de le faire seraient:

  1. Itérez sur le fichier ligne par ligne et breakaprès les Nlignes.

  2. Itérez le fichier ligne par ligne en utilisant la next()méthode Ntimes. (Il s'agit essentiellement d'une syntaxe différente pour ce que fait la réponse principale.)

Voici le code:

# Method 1:
with open("fileName", "r") as f:
    counter = 0
    for line in f:
        print line
        counter += 1
        if counter == N: break

# Method 2:
with open("fileName", "r") as f:
    for i in xrange(N):
        line = f.next()
        print line

En fin de compte, tant que vous n'utilisez pas readlines()ou enumeraten'introduisez pas le fichier entier en mémoire, vous avez de nombreuses options.

FatihAkici
la source
3

manière la plus pratique par moi-même:

LINE_COUNT = 3
print [s for (i, s) in enumerate(open('test.txt')) if i < LINE_COUNT]

Solution basée sur la compréhension de liste La fonction open () supporte une interface d'itération. Enumerate () couvre open () et retourne les tuples (index, item), puis nous vérifions que nous sommes dans une plage acceptée (si i <LINE_COUNT) et ensuite imprimons simplement le résultat.

Profitez du Python. ;)

Maxim Plaksin
la source
Cela semble être une alternative légèrement plus complexe à [next(file) for _ in range(LINE_COUNT)].
AMC
3

Pour les 5 premières lignes, faites simplement:

N=5
with open("data_file", "r") as file:
    for i in range(N):
       print file.next()
Surya
la source
2

Si vous voulez quelque chose qui évidemment (sans chercher des trucs ésotériques dans les manuels) fonctionne sans importations et essayez / sauf et fonctionne sur une bonne gamme de versions de Python 2.x (2.2 à 2.6):

def headn(file_name, n):
    """Like *x head -N command"""
    result = []
    nlines = 0
    assert n >= 1
    for line in open(file_name):
        result.append(line)
        nlines += 1
        if nlines >= n:
            break
    return result

if __name__ == "__main__":
    import sys
    rval = headn(sys.argv[1], int(sys.argv[2]))
    print rval
    print len(rval)
John Machin
la source
2

Si vous avez un très gros fichier, et en supposant que vous voulez que la sortie soit un tableau numpy, l'utilisation de np.genfromtxt gèlera votre ordinateur. C'est tellement mieux d'après mon expérience:

def load_big_file(fname,maxrows):
'''only works for well-formed text file of space-separated doubles'''

rows = []  # unknown number of lines, so use list

with open(fname) as f:
    j=0        
    for line in f:
        if j==maxrows:
            break
        else:
            line = [float(s) for s in line.split()]
            rows.append(np.array(line, dtype = np.double))
            j+=1
return np.vstack(rows)  # convert list of vectors to array
cacosomoza
la source
Si vous avez un très gros fichier, et en supposant que vous voulez que la sortie soit un tableau numpy C'est un ensemble assez unique de restrictions, je ne vois pas vraiment d'avantages à cela par rapport aux alternatives.
AMC
1

À partir de Python 2.6, vous pouvez profiter de fonctions plus sophistiquées dans la classe de base IO. Ainsi, la réponse la mieux notée ci-dessus peut être réécrite comme suit:

    with open("datafile") as myfile:
       head = myfile.readlines(N)
    print head

(Vous n'avez pas à vous soucier du fait que votre fichier contient moins de N lignes car aucune exception StopIteration n'est levée.)

Steve Bading
la source
25
Selon la documentation, N est le nombre d' octets à lire, pas le nombre de lignes .
Mark Mikofski
4
N est le nombre d'octets!
qed
5
Sensationnel. Parlez d'une mauvaise dénomination. Le nom de la fonction mentionne linesmais l'argument fait référence à bytes.
ArtOfWarfare
0

Cela a fonctionné pour moi

f = open("history_export.csv", "r")
line= 5
for x in range(line):
    a = f.readline()
    print(a)
Sukanta
la source
Pourquoi ne pas utiliser un gestionnaire de contexte? En tout cas, je ne vois pas comment cela améliore les nombreuses réponses existantes.
AMC
0

Cela fonctionne pour Python 2 et 3:

from itertools import islice

with open('/tmp/filename.txt') as inf:
    for line in islice(inf, N, N+M):
        print(line)
sandyp
la source
C'est pratiquement identique à la première réponse vieille de dix ans .
AMC
0

fname = input("Enter file name: ")
num_lines = 0

with open(fname, 'r') as f: #lines count
    for line in f:
        num_lines += 1

num_lines_input = int (input("Enter line numbers: "))

if num_lines_input <= num_lines:
    f = open(fname, "r")
    for x in range(num_lines_input):
        a = f.readline()
        print(a)

else:
    f = open(fname, "r")
    for x in range(num_lines_input):
        a = f.readline()
        print(a)
        print("Don't have", num_lines_input, " lines print as much as you can")


print("Total lines in the text",num_lines)
Shakirul
la source
-1
#!/usr/bin/python

import subprocess

p = subprocess.Popen(["tail", "-n 3", "passlist"], stdout=subprocess.PIPE)

output, err = p.communicate()

print  output

Cette méthode a fonctionné pour moi

Mansur Ali
la source
Ce n'est pas vraiment une solution Python, cependant.
AMC
Je ne comprends même pas ce qui est écrit dans votre réponse. Veuillez ajouter quelques explications.
Alexei Marinichenko