Para escrever uma função lenta, basta usar yield
:
def read_in_chunks(file_object, chunk_size=1024):
"""Lazy function (generator) to read a file piece by piece.
Default chunk size: 1k."""
while True:
data = file_object.read(chunk_size)
if not data:
break
yield data
with open('really_big_file.dat') as f:
for piece in read_in_chunks(f):
process_data(piece)
Outra opção seria usar iter
e uma função auxiliar:
f = open('really_big_file.dat')
def read1k():
return f.read(1024)
for piece in iter(read1k, ''):
process_data(piece)
Se o arquivo for baseado em linhas, o objeto de arquivo já será um gerador lento de linhas:
for line in open('really_big_file.dat'):
process_data(line)
f = open('really_big_file.dat')
é apenas um ponteiro sem consumo de memória? (Quero dizer que a memória consumida é a mesma, independentemente do tamanho do arquivo?) Como isso afetará o desempenho se eu usar urllib.readline () em vez de f.readline ()?rb
como @Tal Weiss mencionado; e faltando umafile.close()
declaração (poderia usarwith open('really_big_file.dat', 'rb') as f:
para realizar mesma; Consulte aqui para outra implementação concisa'rb'
é , não está faltando.'b'
dados dele provavelmente estarão corrompidos . A partir dos documentos -Python on Windows makes a distinction between text and binary files; [...] it’ll corrupt binary data like that in JPEG or EXE files. Be very careful to use binary mode when reading and writing such files.
Se o seu computador, SO e python forem de 64 bits , você poderá usar o módulo mmap para mapear o conteúdo do arquivo na memória e acessá-lo com índices e fatias. Aqui está um exemplo da documentação:
Se o seu computador, sistema operacional ou python tiver 32 bits , os arquivos grandes do mmap podem reservar grandes partes do seu espaço de endereço e deixar seu programa de memória com fome .
fonte
file.readlines()
recebe um argumento de tamanho opcional que aproxima o número de linhas lidas nas linhas retornadas.fonte
.read()
não usar.readlines()
. Se o arquivo for binário, não haverá quebras de linha.Já existem muitas respostas boas, mas se seu arquivo inteiro estiver em uma única linha e você ainda desejar processar "linhas" (em oposição a blocos de tamanho fixo), essas respostas não ajudarão.
99% do tempo, é possível processar arquivos linha por linha. Então, como sugerido nesta resposta , você pode usar o próprio objeto de arquivo como gerador lento:
No entanto, uma vez encontrei um arquivo de linha única muito grande (quase), onde o separador de linha não era, de fato,
'\n'
mas'|'
.'|'
para'\n'
antes do processamento também estava fora de questão, porque alguns dos campos deste csv continham'\n'
(entrada de usuário de texto livre).Para esse tipo de situação, criei o seguinte snippet:
Consegui usá-lo com sucesso para resolver meu problema. Foi extensivamente testado, com vários tamanhos de bloco.
Conjunto de testes, para quem quer se convencer.
fonte
ATUALIZAÇÃO: A abordagem é melhor explicada em https://stackoverflow.com/a/4566523/38592
fonte
Consulte a documentação oficial do python https://docs.python.org/zh-cn/3/library/functions.html?#iter
Talvez este método seja mais pitônico:
fonte
Eu acho que podemos escrever assim:
fonte
não tenho permissão para comentar devido à minha baixa reputação, mas a solução SilentGhosts deve ser muito mais fácil com file.readlines ([sizehint])
métodos de arquivo python
edit: SilentGhost está certo, mas isso deve ser melhor do que:
fonte
Estou em uma situação parecida. Não está claro se você sabe o tamanho do pedaço em bytes; Normalmente não, mas o número de registros (linhas) necessário é conhecido:
Atualização : Obrigado nosklo. Aqui está o que eu quis dizer. Quase funciona, exceto que perde uma linha 'entre' pedaços.
O truque sem perder linhas, mas não parece muito agradável.
fonte
Para processar linha por linha, esta é uma solução elegante:
Contanto que não haja linhas em branco.
fonte
open
você já oferece. Um arquivo já é um iterador sobre suas linhas.você pode usar o seguinte código.
open () retorna um objeto de arquivo
então use os.stat para obter tamanho
fonte