Estoy usando un bucle for para leer un archivo, pero solo quiero leer líneas específicas, por ejemplo, las líneas 26 y 30. ¿Hay alguna característica incorporada para lograr esto?
enumerate(x)utiliza x.next, por lo que no necesita todo el archivo en la memoria.
Alok Singhal
3
Mi pequeño problema con esto es que A) Quieres usarlo en lugar del par abierto / cerrado y así mantener el cuerpo corto, B) Pero el cuerpo no es tan corto. Suena como una compensación entre velocidad / espacio y ser Pythonic. No estoy seguro de cuál sería la mejor solución.
Hamish Grubijan
55
con está sobrevalorado, Python se llevó bien durante más de 13 años sin él
Dan D.
38
@Dan D. La electricidad está sobrevalorada, la humanidad se llevó bien durante más de 200 mil años sin ella. ;-) 'with' lo hace más seguro, más legible y una línea más corta.
Romain Vincent
99
por qué usar for loop, no creo que entiendas el significado de big file. El ciclo tardará años en llegar al índice
Use fileobject.readlines()o for line in fileobjectcomo una solución rápida para archivos pequeños.
Úselo linecachepara una solución más elegante, que será bastante rápida para leer muchos archivos, posible repetidamente.
Siga los consejos de @ Alok y utilícelosenumerate() para archivos que pueden ser muy grandes y que no caben en la memoria. Tenga en cuenta que el uso de este método puede disminuir porque el archivo se lee secuencialmente.
Agradable. Acabo de mirar la fuente del linecachemódulo y parece que lee todo el archivo en la memoria. Entonces, si el acceso aleatorio es más importante que la optimización de tamaño, linecachees el mejor método.
Alok Singhal
77
con linecache.getlin ('some_file', 4) obtengo la cuarta línea, no la quinta.
Juan
Dato curioso: si utiliza un conjunto en lugar de la lista en el segundo ejemplo, obtendrá O (1) tiempo de ejecución. Buscar en una lista es O (n). Los conjuntos internos se representan como hashes, y es por eso que obtienes el tiempo de ejecución O (1). no es un gran problema en este ejemplo, pero si usa una lista grande de números y le preocupa la eficiencia, entonces los conjuntos son el camino a seguir.
rady
linecacheahora parece que solo funciona para los archivos fuente de Python
Paul H
También puede usar linecache.getlines('/etc/passwd')[0:4]para leer en la primera, segunda, tercera y cuarta línea.
zyy
30
Un enfoque rápido y compacto podría ser:
def picklines(thefile, whatlines):return[x for i, x in enumerate(thefile)if i in whatlines]
esto acepta cualquier objeto abierto similar a un archivo thefile(dejando a la persona que llama si debe abrirse desde un archivo de disco, o por ejemplo, a través de un socket u otra secuencia similar a un archivo) y un conjunto de índices de línea basados en cero whatlines, y devuelve un lista, con poca huella de memoria y velocidad razonable. Si el número de líneas a devolver es enorme, es posible que prefiera un generador:
def yieldlines(thefile, whatlines):return(x for i, x in enumerate(thefile)if i in whatlines)
que básicamente solo es bueno para hacer un bucle: tenga en cuenta que la única diferencia proviene del uso de paréntesis redondeados en lugar de cuadrados en la returndeclaración, haciendo una comprensión de lista y una expresión generadora respectivamente.
Además, tenga en cuenta que, a pesar de la mención de "líneas" y "archivo", estas funciones son mucho, mucho más generales: funcionarán en cualquier iterable, ya sea un archivo abierto o cualquier otro, devolviendo una lista (o generador) de elementos basado en sus números de artículo progresivos. Por lo tanto, sugeriría usar nombres generales más apropiados ;-).
@ephemient, no estoy de acuerdo: el genexp se lee sin problemas y perfectamente.
Alex Martelli
Excelente y elegante solución, gracias! De hecho, incluso los archivos grandes deben ser compatibles, con la expresión del generador. No puede ser más elegante que esto, ¿verdad? :)
Samuel Lampa
Buena solución, ¿cómo se compara esto con la propuesta por @AdamMatan? La solución de Adam podría ser más rápida ya que explota información adicional (los números de línea aumentan monótonamente) lo que podría conducir a una parada temprana. Tengo un archivo de 10GB que no puedo cargar en la memoria.
Mannaggia
2
@Mannaggia No se enfatiza lo suficiente en esta respuesta, pero whatlinesdebería ser una set, porque if i in whatlinesse ejecutará más rápido con un conjunto en lugar de una lista (ordenada). No lo noté primero y, en su lugar, ideé mi propia solución fea con una lista ordenada (donde no tenía que escanear una lista cada vez, mientras if i in whatlineslo hacía), pero la diferencia en el rendimiento fue insignificante (con mis datos) y esto La solución es mucho más elegante.
Esto lee todo el archivo en la memoria. También podría llamar a file.read (). Split ('\ n') y luego usar búsquedas de índice de matriz para obtener la línea de interés ...
rebanada Un objeto que generalmente contiene una porción de una secuencia. Se crea un segmento utilizando la notación de subíndice, [] con dos puntos entre los números cuando se dan varios, como en variable_name [1: 3: 5]. La notación de corchete (subíndice) usa objetos de división internamente (o en versiones anteriores, __getslice __ () y __setslice __ ()).
Aunque la notación de corte no es directamente aplicable a los iteradores en general, el itertoolspaquete contiene una función de reemplazo:
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
La ventaja adicional de la función es que no lee el iterador hasta el final. Entonces puedes hacer cosas más complejas:
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
Y para responder la pregunta original:
# how to read lines #26 and #30In[365]: list(islice(xrange(1,100),25,30,4))Out[365]:[26,30]
Con mucho, el mejor enfoque cuando se trabaja con archivos grandes. Mi programa pasó de consumir 8GB + a casi nada. El cambio fue el uso de la CPU que pasó de ~ 15% a ~ 40%, pero el procesamiento real del archivo fue un 70% más rápido. Tomaré ese tradoff todo el día. ¡Gracias! 🎉🎉🎉
GollyJer
1
Esto me parece lo más pitónico. ¡Gracias!
ipetrik
10
Leer archivos es increíblemente rápido. Leer un archivo de 100 MB lleva menos de 0.1 segundos (vea mi artículo Leer y escribir archivos con Python ). Por lo tanto, debe leerlo completamente y luego trabajar con las líneas individuales.
Lo que la mayoría de las respuestas hacen aquí no es incorrecto, sino un mal estilo. La apertura de archivos siempre debe realizarse withya que se asegura de que el archivo se cierre nuevamente.
Entonces deberías hacerlo así:
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
Archivos enormes
Si tiene un gran archivo y el consumo de memoria es una preocupación, puede procesarlo línea por línea:
with open("path/to/file.txt")as f:for i, line in enumerate(f):pass# process line i
En mi opinión, es un estilo realmente malo leer un archivo completo de longitud desconocida, solo para obtener las primeras 30 líneas ... ¿qué es sobre el consumo de memoria ... y qué es sobre las secuencias sin fin?
return42
@ return42 Depende mucho de la aplicación. Para muchos, está muy bien suponer que un archivo de texto tiene un tamaño mucho menor que la memoria disponible. Si tiene archivos potencialmente grandes, he editado mi respuesta.
Martin Thoma
gracias por su adición, que es lo mismo que alok answer . Y lo siento, no, no creo que esto dependa de la aplicación. En mi opinión, siempre es mejor no leer más líneas de las que necesita.
regreso42
7
Algunos de estos son encantadores, pero se puede hacer mucho más simple:
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)
Eso usará simplemente el corte de listas, carga todo el archivo, pero la mayoría de los sistemas minimizarán el uso de memoria de manera apropiada, es más rápido que la mayoría de los métodos anteriores y funciona en mis archivos de datos 10G +. ¡Buena suerte!
Puede hacer una llamada a seek () que posiciona su cabeza de lectura en un byte especificado dentro del archivo. Esto no lo ayudará a menos que sepa exactamente cuántos bytes (caracteres) están escritos en el archivo antes de la línea que desea leer. Quizás su archivo esté estrictamente formateado (¿cada línea tiene un número X de bytes?) O puede contar el número de caracteres usted mismo (recuerde incluir caracteres invisibles como saltos de línea) si realmente desea aumentar la velocidad.
De lo contrario, debe leer cada línea antes de la línea que desee, según una de las muchas soluciones que ya se proponen aquí.
Si su archivo de texto grande fileestá estrictamente bien estructurado (lo que significa que cada línea tiene la misma longitud l), puede usar para la nlínea -th
with open(file)as f:
f.seek(n*l)
line = f.readline()
last_pos = f.tell()
Descargo de responsabilidad ¡ Esto solo funciona para archivos con la misma longitud!
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, mi chico favorito! Esto podría beneficiarse de una declaración con.
Hamish Grubijan
2
Prefiero este enfoque porque es más general, es decir, puede usarlo en un archivo, en el resultado de f.readlines(), en un StringIOobjeto, lo que sea:
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']
Aquí están mis pequeños 2 centavos, por lo que vale;)
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])
Los objetos de archivo tienen un método .readlines () que le dará una lista de los contenidos del archivo, una línea por elemento de la lista. Después de eso, puede usar técnicas de corte de lista normales.
Esta no es una respuesta válida. después de que la primera llamada al readlines()iterador se agote y la segunda llamada devuelva una lista vacía o arroje un error (no recuerdo cuál)
Paul H
1
Puede hacerlo de manera muy simple con esta sintaxis que alguien ya mencionó, pero es, con mucho, la forma más fácil de hacerlo:
Para imprimir ciertas líneas en un archivo de texto. Cree una lista "lines2print" y luego simplemente imprima cuando la enumeración esté "en" la lista lines2print. Para deshacerse de '\ n' extra, use line.strip () o line.strip ('\ n'). Simplemente me gusta "lista de comprensión" y trato de usar cuando puedo. Me gusta el método "con" para leer archivos de texto para evitar dejar un archivo abierto por cualquier motivo.
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]
o si la lista es pequeña, simplemente escriba la lista como una lista en la comprensión.
with open("filepath",'r')as fp:[print(x.strip())for ei,x in enumerate(fp)if ei in[26,30]]
Para imprimir la línea deseada. Para imprimir la línea por encima / debajo de la línea requerida.
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()
ejecutar ----> dline ("D: \ dummy.txt", 6) es decir, dline ("ruta del archivo", número_línea, si desea que la línea superior de la línea buscada dé 1 para el -1 inferior, este es el valor predeterminado opcional ser tomado 0)
Si desea leer líneas específicas, como la línea que comienza después de alguna línea de umbral, puede usar los siguientes códigos,
file = open("files.txt","r")
lines = file.readlines() ## convert to list of lines
datas = lines[11:] ## raed the specific lines
Da el resultado incorrecto, ya que no puede usar líneas de lectura y líneas de lectura así (cada una cambia la posición de lectura actual).
Lamento haber pasado por alto un error ENORME en mi primer código. El error se ha corregido y el código actual debería funcionar como se esperaba. Gracias por señalar mi error, Roger Pate.
Respuestas:
Si el archivo a leer es grande y no desea leer todo el archivo en la memoria de una vez:
Tenga en cuenta que
i == n-1
para lan
línea th.En Python 2.6 o posterior:
fuente
enumerate(x)
utilizax.next
, por lo que no necesita todo el archivo en la memoria.big file
. El ciclo tardará años en llegar al índiceLa respuesta rápida:
o:
Hay una solución más elegante para extraer muchas líneas: linecache (cortesía de "python: ¿cómo saltar a una línea particular en un archivo de texto enorme?" , Una pregunta anterior de stackoverflow.com).
Citando la documentación de Python vinculada anteriormente:
Cambiar el
4
a su número de línea deseado, y listo. Tenga en cuenta que 4 traería la quinta línea ya que el conteo se basa en cero.Si el archivo puede ser muy grande y causar problemas al leerlo en la memoria, puede ser una buena idea tomar el consejo de @ Alok y usar enumerate () .
Para concluir:
fileobject.readlines()
ofor line in fileobject
como una solución rápida para archivos pequeños.linecache
para una solución más elegante, que será bastante rápida para leer muchos archivos, posible repetidamente.enumerate()
para archivos que pueden ser muy grandes y que no caben en la memoria. Tenga en cuenta que el uso de este método puede disminuir porque el archivo se lee secuencialmente.fuente
linecache
módulo y parece que lee todo el archivo en la memoria. Entonces, si el acceso aleatorio es más importante que la optimización de tamaño,linecache
es el mejor método.linecache
ahora parece que solo funciona para los archivos fuente de Pythonlinecache.getlines('/etc/passwd')[0:4]
para leer en la primera, segunda, tercera y cuarta línea.Un enfoque rápido y compacto podría ser:
esto acepta cualquier objeto abierto similar a un archivo
thefile
(dejando a la persona que llama si debe abrirse desde un archivo de disco, o por ejemplo, a través de un socket u otra secuencia similar a un archivo) y un conjunto de índices de línea basados en cerowhatlines
, y devuelve un lista, con poca huella de memoria y velocidad razonable. Si el número de líneas a devolver es enorme, es posible que prefiera un generador:que básicamente solo es bueno para hacer un bucle: tenga en cuenta que la única diferencia proviene del uso de paréntesis redondeados en lugar de cuadrados en la
return
declaración, haciendo una comprensión de lista y una expresión generadora respectivamente.Además, tenga en cuenta que, a pesar de la mención de "líneas" y "archivo", estas funciones son mucho, mucho más generales: funcionarán en cualquier iterable, ya sea un archivo abierto o cualquier otro, devolviendo una lista (o generador) de elementos basado en sus números de artículo progresivos. Por lo tanto, sugeriría usar nombres generales más apropiados ;-).
fuente
whatlines
debería ser unaset
, porqueif i in whatlines
se ejecutará más rápido con un conjunto en lugar de una lista (ordenada). No lo noté primero y, en su lugar, ideé mi propia solución fea con una lista ordenada (donde no tenía que escanear una lista cada vez, mientrasif i in whatlines
lo hacía), pero la diferencia en el rendimiento fue insignificante (con mis datos) y esto La solución es mucho más elegante.En aras de ofrecer otra solución:
Espero que esto sea rápido y fácil :)
fuente
si quieres la linea 7
fuente
close()
el archivo al abrirlo de esta manera?En aras de la exhaustividad, aquí hay una opción más.
Comencemos con una definición de documentos de Python :
Aunque la notación de corte no es directamente aplicable a los iteradores en general, el
itertools
paquete contiene una función de reemplazo:La ventaja adicional de la función es que no lee el iterador hasta el final. Entonces puedes hacer cosas más complejas:
Y para responder la pregunta original:
fuente
Leer archivos es increíblemente rápido. Leer un archivo de 100 MB lleva menos de 0.1 segundos (vea mi artículo Leer y escribir archivos con Python ). Por lo tanto, debe leerlo completamente y luego trabajar con las líneas individuales.
Lo que la mayoría de las respuestas hacen aquí no es incorrecto, sino un mal estilo. La apertura de archivos siempre debe realizarse
with
ya que se asegura de que el archivo se cierre nuevamente.Entonces deberías hacerlo así:
Archivos enormes
Si tiene un gran archivo y el consumo de memoria es una preocupación, puede procesarlo línea por línea:
fuente
Algunos de estos son encantadores, pero se puede hacer mucho más simple:
Eso usará simplemente el corte de listas, carga todo el archivo, pero la mayoría de los sistemas minimizarán el uso de memoria de manera apropiada, es más rápido que la mayoría de los métodos anteriores y funciona en mis archivos de datos 10G +. ¡Buena suerte!
fuente
Puede hacer una llamada a seek () que posiciona su cabeza de lectura en un byte especificado dentro del archivo. Esto no lo ayudará a menos que sepa exactamente cuántos bytes (caracteres) están escritos en el archivo antes de la línea que desea leer. Quizás su archivo esté estrictamente formateado (¿cada línea tiene un número X de bytes?) O puede contar el número de caracteres usted mismo (recuerde incluir caracteres invisibles como saltos de línea) si realmente desea aumentar la velocidad.
De lo contrario, debe leer cada línea antes de la línea que desee, según una de las muchas soluciones que ya se proponen aquí.
fuente
Si su archivo de texto grande
file
está estrictamente bien estructurado (lo que significa que cada línea tiene la misma longitudl
), puede usar para lan
línea -thDescargo de responsabilidad ¡ Esto solo funciona para archivos con la misma longitud!
fuente
Qué tal esto:
fuente
Si no le importa importar, fileinput hace exactamente lo que necesita (es decir, puede leer el número de línea de la línea actual)
fuente
fuente
Prefiero este enfoque porque es más general, es decir, puede usarlo en un archivo, en el resultado de
f.readlines()
, en unStringIO
objeto, lo que sea:fuente
Aquí están mis pequeños 2 centavos, por lo que vale;)
fuente
Un cambio mejor y menor para la respuesta de Alok Singhal
fuente
Los objetos de archivo tienen un método .readlines () que le dará una lista de los contenidos del archivo, una línea por elemento de la lista. Después de eso, puede usar técnicas de corte de lista normales.
http://docs.python.org/library/stdtypes.html#file.readlines
fuente
@OP, puedes usar enumerate
fuente
Usando la instrucción with, esto abre el archivo, imprime las líneas 26 y 30 y luego cierra el archivo. ¡Sencillo!
fuente
readlines()
iterador se agote y la segunda llamada devuelva una lista vacía o arroje un error (no recuerdo cuál)Puede hacerlo de manera muy simple con esta sintaxis que alguien ya mencionó, pero es, con mucho, la forma más fácil de hacerlo:
fuente
Para imprimir la línea n. ° 3,
Autor original: Frank Hofmann
fuente
Bastante rápido y al grano.
Para imprimir ciertas líneas en un archivo de texto. Cree una lista "lines2print" y luego simplemente imprima cuando la enumeración esté "en" la lista lines2print. Para deshacerse de '\ n' extra, use line.strip () o line.strip ('\ n'). Simplemente me gusta "lista de comprensión" y trato de usar cuando puedo. Me gusta el método "con" para leer archivos de texto para evitar dejar un archivo abierto por cualquier motivo.
o si la lista es pequeña, simplemente escriba la lista como una lista en la comprensión.
fuente
Para imprimir la línea deseada. Para imprimir la línea por encima / debajo de la línea requerida.
ejecutar ----> dline ("D: \ dummy.txt", 6) es decir, dline ("ruta del archivo", número_línea, si desea que la línea superior de la línea buscada dé 1 para el -1 inferior, este es el valor predeterminado opcional ser tomado 0)
fuente
Si desea leer líneas específicas, como la línea que comienza después de alguna línea de umbral, puede usar los siguientes códigos,
file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines
fuente
fuente
Creo que esto funcionaria
fuente