Leggi le prime N righe di un file in Python


150

Abbiamo un grande file di dati grezzi che vorremmo tagliare ad una dimensione specificata. Ho esperienza in .net c #, tuttavia vorrei farlo in Python per semplificare le cose e per interesse.

Come farei per ottenere le prime N righe di un file di testo in Python? Il sistema operativo utilizzato avrà effetti sull'implementazione?


posso dare n come argomento da riga di comando
Nons

Risposte:


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)

Ecco un altro modo (sia Python 2 che 3)

from itertools import islice
with open("datafile") as myfile:
    head = list(islice(myfile, N))
print head

1
Grazie, è davvero molto utile. Qual è la differenza tra i due? (in termini di prestazioni, librerie richieste, compatibilità ecc.)?
Russell,

1
Mi aspetto che le prestazioni siano simili, forse il primo ad essere leggermente più veloce. Ma il primo non funzionerà se il file non ha almeno N righe. È consigliabile misurare le prestazioni rispetto ad alcuni dati tipici con cui verranno utilizzati.
John La Rooy,

1
L'istruzione with funziona su Python 2.6 e richiede un'istruzione di importazione aggiuntiva su 2.5. Per la versione 2.4 o precedente, dovresti riscrivere il codice con un tentativo ... tranne il blocco. Stilisticamente, preferisco la prima opzione, anche se come detto la seconda è più robusta per i file brevi.
Alasdair,

1
islice è probabilmente più veloce in quanto è implementato in C.
Alice Purcell,

22
Tieni presente che se i file hanno meno di N righe questo genererà l'eccezione StopIteration che devi gestire
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)

23
Io rabbrividisco ogni volta che vedo f = open("file")senza eccezioni gestire per chiudere il file. Il modo Pythonic di gestire i file è con un gestore di contesto, cioè usando l'istruzione with. Questo è trattato nel tutorial Python di input output . "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
Perché aprire il file in modalità append?
AMC

13

Se si desidera leggere rapidamente le prime righe e non si preoccupano delle prestazioni, è possibile utilizzare .readlines()quale oggetto elenco di restituzione e quindi dividere l'elenco.

Ad esempio per le prime 5 righe:

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

Nota: l'intero file viene letto, quindi non è il massimo dal punto di vista delle prestazioni, ma è facile da usare, veloce da scrivere e facile da ricordare, quindi se vuoi semplicemente eseguire un calcolo una tantum è molto conveniente

print firstNlines

Un vantaggio rispetto alle altre risposte è la possibilità di selezionare facilmente l'intervallo di linee, ad esempio saltando le prime 10 linee [10:30]o le ultime 10 [:-10]o prendendo solo le linee pari [::2].


2
La risposta migliore è probabilmente molto più efficiente, ma questa funziona come un incantesimo per file di piccole dimensioni.
T.Chmelevskij

2
Si noti che questo in realtà legge prima l'intero file in un elenco (myfile.readlines ()) e quindi unisce le prime 5 righe di esso.
AbdealiJK,

2
Questo dovrebbe essere evitato.
anilbey,

1
Non vedo alcun motivo per usarlo, non è più semplice delle soluzioni molto più efficienti.
AMC

@AMC grazie per il feedback, lo uso nella console per esplorare i dati quando devo dare un'occhiata veloce alle prime righe, mi fa solo risparmiare tempo nella scrittura del codice.
GM

9

Quello che faccio è chiamare le linee N usando pandas. Penso che la performance non sia la migliore, ma per esempio se N=1000:

import pandas as pd
yourfile = pd.read('path/to/your/file.csv',nrows=1000)

3
Meglio sarebbe usare l' nrowsopzione, che può essere impostata su 1000 e l'intero file non viene caricato. pandas.pydata.org/pandas-docs/stable/generated/… In generale, Panda ha questa e altre tecniche di salvataggio della memoria per file di grandi dimensioni.
philshem l'

Si hai ragione. Ho appena corretto. Scusa per l'errore.
Cro-Magnon,

1
Potresti anche voler aggiungere sepper definire un delimitatore di colonna (che non dovrebbe verificarsi in un file non CSV)
philshem,

1
@ Cro-Magnon Non riesco a trovare la pandas.read()funzione nella documentazione, conosci qualche informazione sull'argomento?
AMC

6

Non esiste un metodo specifico per leggere il numero di righe esposte dall'oggetto file.

Immagino che il modo più semplice sarebbe seguire:

lines =[]
with open(file_name) as f:
    lines.extend(f.readline() for i in xrange(N))

Questo è qualcosa che avevo effettivamente inteso. Tuttavia, ho pensato di aggiungere ogni riga all'elenco. Grazie.
artdanil,

4

Basato sulla risposta più votata da gnibbler (20 novembre 2009 alle 0:27): questa classe aggiunge il metodo head () e tail () all'oggetto file.

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:]

Uso:

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

4

I due modi più intuitivi per farlo sarebbero:

  1. Scorrere sul file riga per riga e breakdopo le Nrighe.

  2. Scorrere il file riga per riga utilizzando i tempi del next()metodo N. (Questa è essenzialmente solo una sintassi diversa per ciò che fa la risposta principale.)

Ecco il codice:

# 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

La linea di fondo è che, purché non si utilizzi readlines()o si enumerateingaggi l'intero file in memoria, si hanno molte opzioni.


3

il modo più comodo per conto mio:

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

Soluzione basata su Comprensione elenco La funzione open () supporta un'interfaccia di iterazione. Enumerate () copre open () e restituisce tuple (indice, elemento), quindi controlliamo di trovarci all'interno di un intervallo accettato (se i <LINE_COUNT) e quindi semplicemente stampare il risultato.

Goditi il ​​Python. ;)


Questa sembra solo un'alternativa leggermente più complessa a [next(file) for _ in range(LINE_COUNT)].
AMC

3

Per le prime 5 righe, fai semplicemente:

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

2

Se vuoi qualcosa che ovviamente (senza cercare cose esoteriche nei manuali) funziona senza importazioni e prova / tranne e funziona su una buona gamma di versioni di Python 2.x (da 2.2 a 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)

2

Se hai un file molto grande e supponendo che desideri che l'output sia un array intorpidito, l'utilizzo di np.genfromtxt bloccherà il tuo computer. Questo è molto meglio nella mia esperienza:

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

Se hai un file molto grande e supponendo che desideri che l'output sia un array intorpidito Questo è un insieme piuttosto unico di restrizioni, non riesco davvero a vedere alcun vantaggio rispetto alle alternative.
AMC

1

A partire da Python 2.6, puoi trarre vantaggio da funzioni più sofisticate nel clase di base IO. Quindi la risposta più votata sopra può essere riscritta come:

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

(Non devi preoccuparti che il tuo file abbia meno di N righe poiché non viene generata alcuna eccezione StopIteration.)


25
Secondo i documenti N è il numero di byte da leggere, non il numero di righe .
Mark Mikofski,

4
N è il numero di byte!
Qed

5
Wow. Parla di una scarsa denominazione. Il nome della funzione menziona linesma l'argomento si riferisce bytes.
ArtOfWarfare il

0

Questo ha funzionato per me

f = open("history_export.csv", "r")
line= 5
for x in range(line):
    a = f.readline()
    print(a)

Perché non usare un gestore di contesto? In ogni caso, non vedo come questo migliora sulle molte risposte esistenti.
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)

-1
#!/usr/bin/python

import subprocess

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

output, err = p.communicate()

print  output

Questo metodo ha funzionato per me


Questa non è davvero una soluzione Python, però.
AMC

Non capisco nemmeno cosa sia scritto nella tua risposta. Per favore, aggiungi qualche spiegazione.
Alexei Marinichenko,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.