Lea las primeras N líneas de un archivo en Python

150

Tenemos un gran archivo de datos sin procesar que nos gustaría recortar a un tamaño específico. Tengo experiencia en .net c #, sin embargo, me gustaría hacer esto en Python para simplificar las cosas y por interés.

¿Cómo haría para obtener las primeras N líneas de un archivo de texto en Python? ¿El sistema operativo utilizado tendrá algún efecto en la implementación?

Russell
fuente
puedo dar n como argumento de línea de comandos
Nons

Respuestas:

240

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)

Aquí hay otra forma (Python 2 y 3)

from itertools import islice
with open("datafile") as myfile:
    head = list(islice(myfile, N))
print head
John La Rooy
fuente
1
Gracias, eso es muy útil. ¿Cuál es la diferencia entre los dos? (en términos de rendimiento, bibliotecas requeridas, compatibilidad, etc.)?
Russell el
1
Espero que el rendimiento sea similar, tal vez el primero sea un poco más rápido. Pero el primero no funcionará si el archivo no tiene al menos N líneas. Es mejor medir el rendimiento con algunos datos típicos con los que lo usará.
John La Rooy el
1
La declaración with funciona en Python 2.6 y requiere una declaración de importación adicional en 2.5. Para 2.4 o anterior, necesitaría reescribir el código con una prueba ... excepto el bloque. Estilísticamente, prefiero la primera opción, aunque como se mencionó, la segunda es más robusta para archivos cortos.
Alasdair el
1
islice es probablemente más rápido ya que se implementa en C.
Alice Purcell
22
Tener en cuenta que si los archivos tienen menos de N líneas esto elevará StopIteration excepción que debe manejar
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
fuente
23
Me estremezco cada vez que veo f = open("file")sin excepción el manejo para cerrar el archivo. La forma Pythonic de manejar archivos es con un administrador de contexto, es decir, usando la instrucción with. Esto está cubierto en el tutorial de Python de entrada y salida . "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
¿Por qué abrir el archivo en modo agregar?
AMC
13

Si desea leer las primeras líneas rápidamente y no le importa el rendimiento, puede usar el .readlines()que devuelve el objeto de la lista y luego cortar la lista.

Por ejemplo, para las primeras 5 líneas:

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

Nota: todo el archivo se lee, por lo que no es el mejor desde el punto de vista del rendimiento, pero es fácil de usar, rápido de escribir y fácil de recordar, por lo que si desea realizar un cálculo único, es muy conveniente

print firstNlines

Una ventaja en comparación con las otras respuestas es la posibilidad de seleccionar fácilmente el rango de líneas, por ejemplo, omitir las primeras 10 líneas [10:30]o las últimas 10 [:-10]o tomar solo líneas pares [::2].

GM
fuente
2
La respuesta principal es probablemente mucho más eficiente, pero esta funciona de maravilla para archivos pequeños.
T.Chmelevskij
2
Tenga en cuenta que esto realmente lee todo el archivo en una lista primero (myfile.readlines ()) y luego divide las primeras 5 líneas.
AbdealiJK
2
Esto debe ser evitado.
Anilbey
1
No veo ninguna razón para usar esto, no es más simple que las soluciones mucho más eficientes.
AMC
@AMC gracias por los comentarios, lo uso en la consola para explorar los datos cuando tengo que echar un vistazo rápido a las primeras líneas, solo me ahorra tiempo en escribir código.
GM
9

Lo que hago es llamar a las líneas N usando pandas. Creo que el rendimiento no es el mejor, pero por ejemplo si N=1000:

import pandas as pd
yourfile = pd.read('path/to/your/file.csv',nrows=1000)
Cro-Magnon
fuente
3
Mejor sería usar la nrowsopción, que se puede establecer en 1000 y no se carga todo el archivo. pandas.pydata.org/pandas-docs/stable/generated/… En general, pandas tiene esta y otras técnicas de ahorro de memoria para archivos grandes.
philshem
Sí, tiene usted razón. Solo lo corrijo. Lo siento por el error.
Cro-Magnon
1
También es posible que desee agregar sepa definir un delimitador de columna (que no debería ocurrir en un archivo que no CSV)
philshem
1
@ Cro-Magnon No puedo encontrar la pandas.read()función en la documentación, ¿conoce alguna información sobre el tema?
AMC
6

No existe un método específico para leer el número de líneas expuestas por el objeto de archivo.

Supongo que la forma más fácil sería seguir:

lines =[]
with open(file_name) as f:
    lines.extend(f.readline() for i in xrange(N))
artdanil
fuente
Esto es algo que realmente tenía la intención. Sin embargo, pensé en agregar cada línea a la lista. Gracias.
artdanil
4

Basado en la respuesta más votada de gnibbler (20 de noviembre de 2009 a las 0:27): esta clase agrega el método head () y tail () para archivar el objeto.

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)
fdb
fuente
4

Las dos formas más intuitivas de hacer esto serían:

  1. Iterar en el archivo línea por línea y breakdespués de las Nlíneas.

  2. Iterar en el archivo línea por línea usando los tiempos del next()método N. (Esto es esencialmente una sintaxis diferente de lo que hace la respuesta principal).

Aquí está el código:

# 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 conclusión es que, siempre que no use readlines()o enumerateguarde todo el archivo en la memoria, tiene muchas opciones.

FatihAkici
fuente
3

La forma más conveniente por mi cuenta:

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

Solución basada en la comprensión de la lista La función open () admite una interfaz de iteración. El enumerate () cubre las tuplas open () y return (index, item), luego verificamos que estamos dentro de un rango aceptado (si i <LINE_COUNT) y luego simplemente imprimimos el resultado.

Disfruta el Python. ;)

Maxim Plaksin
fuente
Esto simplemente parece una alternativa un poco más compleja para [next(file) for _ in range(LINE_COUNT)].
AMC
3

Para las primeras 5 líneas, simplemente haga:

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

Si desea algo que obviamente (sin buscar cosas esotéricas en los manuales) funcione sin importaciones e intente / excepto y funcione en una gama justa de versiones de Python 2.x (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)
John Machin
fuente
2

Si tiene un archivo realmente grande, y suponiendo que desea que la salida sea una matriz vacía, el uso de np.genfromtxt congelará su computadora. Esto es mucho mejor en mi experiencia:

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
fuente
Si tiene un archivo realmente grande, y suponiendo que desea que la salida sea una matriz numpy. Es un conjunto bastante único de restricciones, realmente no puedo ver ninguna ventaja sobre las alternativas.
AMC
1

A partir de Python 2.6, puede aprovechar funciones más sofisticadas en la clase base IO. Entonces, la respuesta mejor calificada arriba se puede reescribir como:

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

(No tiene que preocuparse de que su archivo tenga menos de N líneas ya que no se produce ninguna excepción StopIteration).

Steve Bading
fuente
25
Según los documentos, N es el número de bytes a leer, no el número de líneas .
Mark Mikofski
44
N es el número de bytes!
qed
55
Guau. Hable acerca de nombres pobres. El nombre de la función menciona linespero el argumento hace referencia bytes.
ArtOfWarfare
0

Esto funciono para mi

f = open("history_export.csv", "r")
line= 5
for x in range(line):
    a = f.readline()
    print(a)
Sukanta
fuente
¿Por qué no usar un administrador de contexto? En cualquier caso, no veo cómo esto mejora en las muchas respuestas existentes.
AMC
0

Esto funciona para Python 2 y 3:

from itertools import islice

with open('/tmp/filename.txt') as inf:
    for line in islice(inf, N, N+M):
        print(line)
sandyp
fuente
Esto es prácticamente idéntico a la respuesta principal de hace una década .
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
fuente
-1
#!/usr/bin/python

import subprocess

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

output, err = p.communicate()

print  output

Este método funcionó para mi

Mansur Ali
fuente
Sin embargo, esta no es realmente una solución de Python.
AMC
Ni siquiera entiendo lo que está escrito en su respuesta. Por favor agregue alguna explicación.
Alexei Marinichenko