Pergunta

Eu tenho um aplicativo que gera alguns grandes arquivos de log> 500 MB.

Escrevi alguns utilitários em Python que me permitem navegar rapidamente no arquivo de log e encontrar dados de interesse. Mas agora recebo alguns conjuntos de dados em que o arquivo é grande demais para carregar tudo na memória.

Assim, quero escanear o documento uma vez, construir um índice e, em seguida, carregue apenas a seção do documento na memória que quero examinar de cada vez.

Isso funciona para mim quando abro um 'arquivo', leia uma linha de cada vez e guarde o deslocamento com o File.Tell (). Eu posso voltar para a seção do arquivo posteriormente com o arquivo.seek (deslocamento, 0).

Meu problema é, no entanto, que posso ter UTF-8 nos arquivos de log, então preciso abri-los com o módulo Codecs (codecs.open(<filename>, 'r', 'utf-8')). Com o objeto resultante, posso chamar procurar e contar, mas eles não correspondem.

Presumo que os codecs precisem fazer alguns buffers ou talvez retorne a contagem de personagens em vez de bytes do Tell?

Existe uma maneira de contornar isso?

Foi útil?

Solução

Se for verdade, isso soa como um bug ou limitação do módulo Codecs, pois provavelmente está confundindo byte e compensações de personagens.

Eu usaria o regular open() função para abrir o arquivo, então seek()/tell() dará a você compensações de bytes que são sempre consistentes. Sempre que quiser ler, use f.readline().decode('utf-8').

Cuidado, porém, que usando o f.read() A função pode atingir você no meio de um caractere de vários bytes, produzindo assim um erro de decodificação UTF-8. readline() sempre funcionará.

Isso não lida com a marca de ordem de byte para você, mas é provável que seus arquivos de log não tenham BOMs de qualquer maneira.

Outras dicas

Para o UTF-8, você não precisa abrir o arquivo com codecs.open. Em vez disso, é confiável ler o arquivo como uma string de byte primeiro e só depois decodificar uma seção individual (invocando o método .decode na string). Quebrar o arquivo nos limites da linha é seguro; A única maneira insegura de dividi-lo seria no meio de um caractere multi-bytes (que você pode reconhecer em seu valor de byte> 128).

Muito do que acontece com o UTF8 em Python faz sentido se você observar como foi feito no Python 3. No seu caso, fará um pouco mais de sentido se você ler o capítulo de arquivos no Python 3: http://diveintopython3.org/files.html

O meio disso, porém, é aquele file.seek e file.tell Trabalhe com posições de bytes, enquanto os caracteres Unicode podem assumir vários bytes. Assim, se você fizer:

f.seek(10)
f.read(1)
f.tell()

Você pode facilmente obter algo diferente 17, dependendo de que comprimento o personagem que você leu era.

ATUALIZAÇÃO: Você não pode procurar/dizer sobre o objeto retornado por codec.open (). Você precisa usar um arquivo normal e decodificar as strings para unicode após a leitura.

Não sei por que não funciona, mas não posso fazê -lo funcionar. A busca parece funcionar apenas uma vez, por exemplo. Então você precisa fechar e reabrir o arquivo, o que obviamente não é útil.

O Tell não usa posições de caracteres, mas não mostra onde está sua posição no fluxo (mas provavelmente onde o objeto de arquivo subjacente está na leitura do disco).

Então, provavelmente por causa de algum tipo de buffer subjacente, você não pode fazê -lo. Mas o desocupação após a leitura funciona muito bem, então vá para isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top