Lendo apenas linhas específicas


Respostas:


253

Se o arquivo a ser lido for grande e você não quiser ler o arquivo inteiro na memória de uma só vez:

fp = open("file")
for i, line in enumerate(fp):
    if i == 25:
        # 26th line
    elif i == 29:
        # 30th line
    elif i > 29:
        break
fp.close()

Observe que i == n-1para a nlinha th.


No Python 2.6 ou posterior:

with open("file") as fp:
    for i, line in enumerate(fp):
        if i == 25:
            # 26th line
        elif i == 29:
            # 30th line
        elif i > 29:
            break

8
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
devssh

159

A resposta rápida:

f=open('filename')
lines=f.readlines()
print lines[25]
print lines[29]

ou:

lines=[25, 29]
i=0
f=open('filename')
for line in f:
    if i in lines:
        print i
    i+=1

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:

>>> import linecache
>>> linecache.getline('/etc/passwd', 4)
'sys:x:3:3:sys:/dev:/bin/sh\n'

Mude 4para 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:

  • 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.

7
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.
21715 Victor K

28

Para oferecer outra solução:

import linecache
linecache.getline('Sample.txt', Number_of_Line)

Espero que seja rápido e fácil :)


1
Espero que seja a melhor solução.
Maniac_user 14/10

2
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


10

Por uma questão de integridade, aqui está mais uma opção.

Vamos começar com uma definição dos documentos python :

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 line
with open('the_file') as lines:
    for line in islice(lines, 99, 100):
        print line

# print each third line until 100
with 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 lines
    for line in islice(lines, 100):
        print line

    # then skip the next 5
    for line in islice(lines, 5):
        pass

    # print the rest
    for line in lines:
        print line

E para responder à pergunta original:

# how to read lines #26 and #30
In [365]: list(islice(xrange(1,100), 25, 30, 4))
Out[365]: [26, 30]

1
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 line
print(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 use

with 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!


4

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.


3

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!


2

Que tal agora:

>>> with open('a', 'r') as fin: lines = fin.readlines()
>>> for i, line in enumerate(lines):
      if i > 30: break
      if i == 26: dox()
      if i == 30: doy()

É verdade, isso é menos eficiente do que o de Alok, mas meu usa uma com a declaração;)
Hamish Grubijan

2

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)


2
def getitems(iterable, items):
  items = list(items) # get a list from any iterable and make our own copy
                      # since we modify it
  if items:
    items.sort()
    for n, v in enumerate(iterable):
      if n == items[0]:
        yield v
        items.pop(0)
        if not items:
          break

print 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 + 1 in 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']

2

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 otherwise
    print "Line: %s\nData: %s\n" % (line[0], line[1])

2

Uma mudança melhor e menor para a resposta de Alok Singhal

fp = open("file")
for i, line in enumerate(fp,1):
    if i == 26:
        # 26th line
    elif i == 30:
        # 30th line
    elif i > 30:
        break
fp.close()


1

@OP, você pode usar enumerar

for n,line in enumerate(open("file")):
    if n+1 in [26,30]: # or n in [25,29] 
       print line.rstrip()

1
file = '/path/to/file_to_be_read.txt'
with open(file) as f:
    print f.readlines()[26]
    print f.readlines()[30]

Usando a instrução with, isso abre o arquivo, imprime as linhas 26 e 30 e depois fecha o arquivo. Simples!


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:

inputFile = open("lineNumbers.txt", "r")
lines = inputFile.readlines()
print (lines[0])
print (lines[2])

1

Para imprimir a linha 3,

line_number = 3

with open(filename,"r") as file:
current_line = 1
for line in file:
    if current_line == line_number:
        print(file.readline())
        break
    current_line += 1

Autor original: Frank Hofmann


1

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.

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

0

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)


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


-1
f = open(filename, 'r')
totalLines = len(f.readlines())
f.close()
f = open(filename, 'r')

lineno = 1
while lineno < totalLines:
    line = f.readline()

    if lineno == 26:
        doLine26Commmand(line)

    elif lineno == 30:
        doLine30Commmand(line)

    lineno += 1
f.close()

7
isso é tão impiedoso quanto possível.
SilentGhost

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.
inspectorG4dget

-1

Eu acho que isso funcionaria

 open_file1 = open("E:\\test.txt",'r')
 read_it1 = open_file1.read()
 myline1 = []
 for line1 in read_it1.splitlines():
 myline1.append(line1)
 print myline1[0]

Já havia uma dúzia de métodos readline quando você postou isso - adicionando outro só aumenta a confusão
duhaime
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.