Estou usando um loop for para ler um arquivo, mas só quero ler linhas específicas, digamos as linhas 26 e 30. Existe algum recurso interno para conseguir isso?
enumerate(x)usa x.next, portanto, não precisa do arquivo inteiro na memória.
Alok Singhal
3
Minha carne pequena com isso é que A) Você deseja usar com o par aberto / fechado e, assim, manter o corpo curto, B) Mas o corpo não é tão curto. Soa como uma troca entre velocidade / espaço e ser pitônico. Não tenho certeza de qual seria a melhor solução.
Hamish Grubijan
5
com é superestimada, python nos dávamos muito bem para mais de 13 anos sem ele
Dan D.
38
@ Dan D. A eletricidade é superestimada, a humanidade se dá bem há mais de 200 mil anos sem ela. ;-) 'with' está tornando-o mais seguro, mais legível e uma linha mais curta.
Romain Vincent
9
por que usar o loop, acho que você não entende o significado de big file. O loop vai levar anos para chegar ao índice
Use fileobject.readlines()ou for line in fileobjectcomo uma solução rápida para arquivos pequenos.
Use linecachepara uma solução mais elegante, que será bastante rápida para ler muitos arquivos, possível repetidamente.
Siga os conselhos do @ Alok e use-osenumerate() em arquivos que podem ser muito grandes e não cabem na memória. Observe que o uso desse método pode ficar lento porque o arquivo é lido sequencialmente.
Agradável. Eu apenas olhei para a fonte do linecachemódulo e parece que ele lê o arquivo inteiro na memória. Portanto, se o acesso aleatório é mais importante que a otimização de tamanho, linecacheé o melhor método.
Alok Singhal
7
com linecache.getlin ('some_file', 4) recebo a quarta linha, não a quinta.
Juan
fato interessante: se você usar um conjunto em vez da lista no segundo exemplo, terá O (1) tempo de execução. Procurar em uma lista é O (n). Conjuntos internos são representados como hashes, e é por isso que você obtém o tempo de execução O (1). não é grande coisa neste exemplo, mas se você estiver usando uma grande lista de números e se preocupa com a eficiência, os conjuntos são o caminho a seguir.
Rady
linecacheagora parece funcionar apenas para arquivos de origem python
Paul H #
Você também pode usar linecache.getlines('/etc/passwd')[0:4]para ler as primeira, segunda, terceira e quarta linhas.
Zyy 04/12/19
30
Uma abordagem rápida e compacta pode ser:
def picklines(thefile, whatlines):return[x for i, x in enumerate(thefile)if i in whatlines]
isso aceita qualquer objeto aberto semelhante a um arquivo thefile(deixando ao chamador se ele deve ser aberto a partir de um arquivo em disco ou via, por exemplo, um soquete ou outro fluxo semelhante a um arquivo) e um conjunto de índices de linha baseados em zero whatlinese retorna um lista, com pouca presença de memória e velocidade razoável. Se o número de linhas a serem retornadas for grande, você pode preferir um gerador:
def yieldlines(thefile, whatlines):return(x for i, x in enumerate(thefile)if i in whatlines)
o que é basicamente bom apenas para repetição - observe que a única diferença vem do uso de parênteses arredondados em vez de quadrados na returndeclaração, fazendo uma compreensão de lista e uma expressão de gerador, respectivamente.
Observe também que, apesar da menção de "linhas" e "arquivo", essas funções são muito, muito mais gerais - elas funcionam em qualquer iterável, seja um arquivo aberto ou outro, retornando uma lista (ou gerador) de itens com base em seus números de itens progressivos. Então, eu sugiro usar nomes gerais mais apropriadamente ;-).
@hememient, eu discordo - o genexp lê de forma suave e perfeita.
Alex Martelli
Solução excelente e elegante, obrigado! De fato, mesmo arquivos grandes devem ser suportados, com a expressão do gerador. Não pode ficar mais elegante que isso, pode? :)
Samuel Lampa
Solução agradável, como isso se compara ao proposto por @AdamMatan? A solução Adam pode ser mais rápida, pois explora informações adicionais (o número de linhas aumenta monotonicamente), o que pode levar a uma parada antecipada. Eu tenho um arquivo de 10 GB que não consigo carregar na memória.
precisa
2
@Annaggia Não é enfatizado o suficiente nesta resposta, mas whatlinesdeve ser um set, porque if i in whatlinesserá executado mais rapidamente com um conjunto do que com uma lista (classificada). Eu não percebi isso primeiro e, em vez disso, criei minha própria solução feia com lista classificada (onde eu não precisava varrer uma lista todas as vezes, enquanto if i in whatlinesfaz exatamente isso), mas a diferença no desempenho era insignificante (com meus dados) e isso solução é muito mais elegante.
Isso lê o arquivo inteiro na memória. Você pode muito bem chamar file.read () split ( '\ n'), em seguida, usar pesquisas de índice de matriz para obter a linha de interesse ....
duhaime
Você poderia fornecer um exemplo @duhaime
anon
14
se você quer a linha 7
line = open ("arquivo.txt", "r"). readlines () [7]
fatia Um objeto geralmente contendo uma parte de uma sequência. Uma fatia é criada usando a notação subscrita, [] com dois pontos entre os números quando vários são fornecidos, como na variável_name [1: 3: 5]. A notação de colchete (subscrito) usa objetos de fatia internamente (ou em versões mais antigas, __getslice __ () e __setslice __ ()).
Embora a notação de fatia não seja diretamente aplicável aos iteradores em geral, o itertoolspacote contém uma função de substituição:
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
A vantagem adicional da função é que ela não lê o iterador até o final. Então você pode fazer coisas mais complexas:
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
E para responder à pergunta original:
# how to read lines #26 and #30In[365]: list(islice(xrange(1,100),25,30,4))Out[365]:[26,30]
De longe, a melhor abordagem ao trabalhar com arquivos grandes. Meu programa passou de consumir 8 GB + a quase nada. O problema foi o uso da CPU, que passou de ~ 15% a ~ 40%, mas o processamento real do arquivo foi 70% mais rápido. Vou levar isso para o dia todo. Te agradece! Gol
GollyJer 26/09/18
1
Isso me parece mais pitônico. Obrigado!
Ipetrik
10
A leitura de arquivos é incrivelmente rápida. A leitura de um arquivo de 100 MB leva menos de 0,1 segundos (consulte meu artigo Lendo e gravando arquivos com Python ). Portanto, você deve lê-lo completamente e depois trabalhar com as linhas únicas.
O que a maioria das respostas aqui faz não é errado, mas tem um estilo ruim. A abertura de arquivos sempre deve ser feita with, pois garante que o arquivo seja fechado novamente.
Então você deve fazer assim:
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
Arquivos enormes
Se houver um grande arquivo e o consumo de memória for uma preocupação, você poderá processá-lo linha por linha:
with open("path/to/file.txt")as f:for i, line in enumerate(f):pass# process line i
Na IMO, é um estilo muito ruim ler um arquivo inteiro de comprimento desconhecido, apenas para obter as primeiras 30 linhas ... o que é o consumo de memória e o que são os fluxos intermináveis?
precisa saber é o seguinte
@ return42 Depende muito da aplicação. Para muitos, é totalmente bom supor que um arquivo de texto tenha um tamanho muito menor que a memória disponível. Se houver arquivos potencialmente enormes, editei minha resposta.
Martin Thoma
obrigado por seu lado, que é o mesmo que alok resposta . E desculpe não, acho que isso não depende do aplicativo. OMI é sempre melhor não ler mais linhas do que você precisa.
precisa saber é o seguinte
7
Alguns deles são adoráveis, mas isso pode ser feito de maneira muito mais simples:
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)
Isso usará simplesmente o faturamento de lista, carregará o arquivo inteiro, mas a maioria dos sistemas minimizará o uso de memória adequadamente, é mais rápido que a maioria dos métodos fornecidos acima e funciona nos meus arquivos de dados 10G +. Boa sorte!
Você pode fazer uma chamada seek () que posiciona sua cabeça de leitura em um byte especificado no arquivo. Isso não ajudará você, a menos que você saiba exatamente quantos bytes (caracteres) estão escritos no arquivo antes da linha que deseja ler. Talvez o seu arquivo esteja formatado estritamente (cada linha tem um número X de bytes?) Ou você pode contar o número de caracteres (lembre-se de incluir caracteres invisíveis, como quebras de linha), se quiser realmente aumentar a velocidade.
Caso contrário, você precisará ler todas as linhas anteriores à linha desejada, conforme uma das muitas soluções já propostas aqui.
Se o seu arquivo de texto grande fileestiver estritamente bem estruturado (o que significa que cada linha tem o mesmo comprimento l), você poderá usar a n-a linha
with open(file)as f:
f.seek(n*l)
line = f.readline()
last_pos = f.tell()
Isenção de responsabilidade Isso funciona apenas para arquivos com o mesmo comprimento!
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, meu cara favorito! Isso pode se beneficiar de uma declaração with.
Hamish Grubijan
2
Prefiro essa abordagem porque é de uso geral, ou seja, você pode usá-la em um arquivo, no resultado de f.readlines(), em um StringIOobjeto, o que for:
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']
Aqui estão meus pequenos 2 centavos, pelo que vale a pena;)
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])
Os objetos de arquivo têm um método .readlines () que fornece uma lista do conteúdo do arquivo, uma linha por item de lista. Depois disso, você pode apenas usar técnicas normais de fatiar listas.
Esta não é uma resposta válida. após a primeira chamada para readlines()o iterador será esgotado e a segunda chamada será ou retornar uma lista vazia ou lançar um erro (não lembro qual)
Paul H
1
Você pode fazer isso de maneira muito simples com esta sintaxe que alguém já mencionou, mas é de longe a maneira mais fácil de fazer isso:
Para imprimir certas linhas em um arquivo de texto. Crie uma lista "lines2print" e imprima apenas quando a enumeração estiver "na" lista de lines2print. Para se livrar de '\ n' extra, use line.strip () ou line.strip ('\ n'). Eu apenas gosto de "compreensão da lista" e tento usar quando posso. Eu gosto do método "with" para ler arquivos de texto, a fim de evitar que um arquivo seja aberto por qualquer 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]
ou se a lista for pequena, basta digitar a lista como uma lista para a compreensão.
with open("filepath",'r')as fp:[print(x.strip())for ei,x in enumerate(fp)if ei in[26,30]]
Para imprimir a linha desejada. Para imprimir a linha acima / abaixo da linha necessária.
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) ou seja, dline ("caminho do arquivo", número da linha, se você quiser a linha superior da linha pesquisada, forneça 1 para menor -1, este é o valor padrão opcional ser tomado 0)
Se você quiser ler linhas específicas, como a linha iniciada após alguma linha de limite, use os seguintes códigos,
file = open("files.txt","r")
lines = file.readlines() ## convert to list of lines
datas = lines[11:] ## raed the specific lines
Dá o resultado errado, pois você não pode usar linhas de leitura e linhas de leitura assim (cada uma muda a posição atual de leitura).
Sinto muito por ter esquecido um erro enorme no meu primeiro código. O erro foi corrigido e o código atual deve funcionar conforme o esperado. Obrigado por apontar meu erro, Roger Pate.
Respostas:
Se o arquivo a ser lido for grande e você não quiser ler o arquivo inteiro na memória de uma só vez:
Observe que
i == n-1
para an
linha th.No Python 2.6 ou posterior:
fonte
enumerate(x)
usax.next
, portanto, não precisa do arquivo inteiro na memória.big file
. O loop vai levar anos para chegar ao índiceA resposta rápida:
ou:
Existe uma solução mais elegante para extrair muitas linhas: linecache (cortesia de "python: como pular para uma linha específica em um grande arquivo de texto?" , Uma pergunta anterior sobre stackoverflow.com).
Citando a documentação do python vinculada acima:
Mude
4
para o número da linha desejada e pronto. Observe que 4 trará a quinta linha, pois a contagem é baseada em zero.Se o arquivo for muito grande e causar problemas ao ler na memória, pode ser uma boa idéia seguir os conselhos de @ Alok e usar enumerate () .
Concluir:
fileobject.readlines()
oufor line in fileobject
como uma solução rápida para arquivos pequenos.linecache
para uma solução mais elegante, que será bastante rápida para ler muitos arquivos, possível repetidamente.enumerate()
em arquivos que podem ser muito grandes e não cabem na memória. Observe que o uso desse método pode ficar lento porque o arquivo é lido sequencialmente.fonte
linecache
módulo e parece que ele lê o arquivo inteiro na memória. Portanto, se o acesso aleatório é mais importante que a otimização de tamanho,linecache
é o melhor método.linecache
agora parece funcionar apenas para arquivos de origem pythonlinecache.getlines('/etc/passwd')[0:4]
para ler as primeira, segunda, terceira e quarta linhas.Uma abordagem rápida e compacta pode ser:
isso aceita qualquer objeto aberto semelhante a um arquivo
thefile
(deixando ao chamador se ele deve ser aberto a partir de um arquivo em disco ou via, por exemplo, um soquete ou outro fluxo semelhante a um arquivo) e um conjunto de índices de linha baseados em zerowhatlines
e retorna um lista, com pouca presença de memória e velocidade razoável. Se o número de linhas a serem retornadas for grande, você pode preferir um gerador:o que é basicamente bom apenas para repetição - observe que a única diferença vem do uso de parênteses arredondados em vez de quadrados na
return
declaração, fazendo uma compreensão de lista e uma expressão de gerador, respectivamente.Observe também que, apesar da menção de "linhas" e "arquivo", essas funções são muito, muito mais gerais - elas funcionam em qualquer iterável, seja um arquivo aberto ou outro, retornando uma lista (ou gerador) de itens com base em seus números de itens progressivos. Então, eu sugiro usar nomes gerais mais apropriadamente ;-).
fonte
whatlines
deve ser umset
, porqueif i in whatlines
será executado mais rapidamente com um conjunto do que com uma lista (classificada). Eu não percebi isso primeiro e, em vez disso, criei minha própria solução feia com lista classificada (onde eu não precisava varrer uma lista todas as vezes, enquantoif i in whatlines
faz exatamente isso), mas a diferença no desempenho era insignificante (com meus dados) e isso solução é muito mais elegante.Para oferecer outra solução:
Espero que seja rápido e fácil :)
fonte
se você quer a linha 7
fonte
close()
abre o arquivo dessa maneira?Por uma questão de integridade, aqui está mais uma opção.
Vamos começar com uma definição dos documentos python :
Embora a notação de fatia não seja diretamente aplicável aos iteradores em geral, o
itertools
pacote contém uma função de substituição:A vantagem adicional da função é que ela não lê o iterador até o final. Então você pode fazer coisas mais complexas:
E para responder à pergunta original:
fonte
A leitura de arquivos é incrivelmente rápida. A leitura de um arquivo de 100 MB leva menos de 0,1 segundos (consulte meu artigo Lendo e gravando arquivos com Python ). Portanto, você deve lê-lo completamente e depois trabalhar com as linhas únicas.
O que a maioria das respostas aqui faz não é errado, mas tem um estilo ruim. A abertura de arquivos sempre deve ser feita
with
, pois garante que o arquivo seja fechado novamente.Então você deve fazer assim:
Arquivos enormes
Se houver um grande arquivo e o consumo de memória for uma preocupação, você poderá processá-lo linha por linha:
fonte
Alguns deles são adoráveis, mas isso pode ser feito de maneira muito mais simples:
Isso usará simplesmente o faturamento de lista, carregará o arquivo inteiro, mas a maioria dos sistemas minimizará o uso de memória adequadamente, é mais rápido que a maioria dos métodos fornecidos acima e funciona nos meus arquivos de dados 10G +. Boa sorte!
fonte
Você pode fazer uma chamada seek () que posiciona sua cabeça de leitura em um byte especificado no arquivo. Isso não ajudará você, a menos que você saiba exatamente quantos bytes (caracteres) estão escritos no arquivo antes da linha que deseja ler. Talvez o seu arquivo esteja formatado estritamente (cada linha tem um número X de bytes?) Ou você pode contar o número de caracteres (lembre-se de incluir caracteres invisíveis, como quebras de linha), se quiser realmente aumentar a velocidade.
Caso contrário, você precisará ler todas as linhas anteriores à linha desejada, conforme uma das muitas soluções já propostas aqui.
fonte
Se o seu arquivo de texto grande
file
estiver estritamente bem estruturado (o que significa que cada linha tem o mesmo comprimentol
), você poderá usar an
-a linhaIsenção de responsabilidade Isso funciona apenas para arquivos com o mesmo comprimento!
fonte
Que tal agora:
fonte
Se você não se importa em importar, o fileinput faz exatamente o que você precisa (você pode ler o número da linha atual)
fonte
fonte
Prefiro essa abordagem porque é de uso geral, ou seja, você pode usá-la em um arquivo, no resultado de
f.readlines()
, em umStringIO
objeto, o que for:fonte
Aqui estão meus pequenos 2 centavos, pelo que vale a pena;)
fonte
Uma mudança melhor e menor para a resposta de Alok Singhal
fonte
Os objetos de arquivo têm um método .readlines () que fornece uma lista do conteúdo do arquivo, uma linha por item de lista. Depois disso, você pode apenas usar técnicas normais de fatiar listas.
http://docs.python.org/library/stdtypes.html#file.readlines
fonte
@OP, você pode usar enumerar
fonte
Usando a instrução with, isso abre o arquivo, imprime as linhas 26 e 30 e depois fecha o arquivo. Simples!
fonte
readlines()
o iterador será esgotado e a segunda chamada será ou retornar uma lista vazia ou lançar um erro (não lembro qual)Você pode fazer isso de maneira muito simples com esta sintaxe que alguém já mencionou, mas é de longe a maneira mais fácil de fazer isso:
fonte
Para imprimir a linha 3,
Autor original: Frank Hofmann
fonte
Bastante rápido e direto ao ponto.
Para imprimir certas linhas em um arquivo de texto. Crie uma lista "lines2print" e imprima apenas quando a enumeração estiver "na" lista de lines2print. Para se livrar de '\ n' extra, use line.strip () ou line.strip ('\ n'). Eu apenas gosto de "compreensão da lista" e tento usar quando posso. Eu gosto do método "with" para ler arquivos de texto, a fim de evitar que um arquivo seja aberto por qualquer motivo.
ou se a lista for pequena, basta digitar a lista como uma lista para a compreensão.
fonte
Para imprimir a linha desejada. Para imprimir a linha acima / abaixo da linha necessária.
execute ----> dline ("D: \ dummy.txt", 6) ou seja, dline ("caminho do arquivo", número da linha, se você quiser a linha superior da linha pesquisada, forneça 1 para menor -1, este é o valor padrão opcional ser tomado 0)
fonte
Se você quiser ler linhas específicas, como a linha iniciada após alguma linha de limite, use os seguintes códigos,
file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines
fonte
fonte
Eu acho que isso funcionaria
fonte