Existem alternativas para o código abaixo:
startFromLine = 141978 # or whatever line I need to jump to
urlsfile = open(filename, "rb", 0)
linesCounter = 1
for line in urlsfile:
if linesCounter > startFromLine:
DoSomethingWithThisLine(line)
linesCounter += 1
Se estou processando um arquivo de texto enorme (~15MB)
com linhas de comprimento desconhecido, mas diferente, e preciso pular para uma linha específica, qual número conheço com antecedência? Eu me sinto mal por processá-los um por um, quando sei que poderia ignorar pelo menos a primeira metade do arquivo. Procurando uma solução mais elegante, se houver alguma.
python
text-files
user63503
fonte
fonte
Respostas:
linecache :
fonte
Você não pode pular sem ler o arquivo pelo menos uma vez, pois você não sabe onde estão as quebras de linha. Você poderia fazer algo como:
fonte
Você realmente não tem muitas opções se as linhas forem de comprimentos diferentes ... infelizmente, você precisa processar os caracteres de final de linha para saber quando avançou para a próxima linha.
Você pode, no entanto, acelerar drasticamente E reduzir o uso de memória alterando o último parâmetro para "abrir" para algo diferente de 0.
0 significa que a operação de leitura do arquivo não tem buffer, o que é muito lento e exige muito do disco. 1 significa que o arquivo está em buffer de linha, o que seria uma melhoria. Qualquer coisa acima de 1 (digamos 8k .. ex .: 8096 ou superior) lê pedaços do arquivo na memória. Você ainda pode acessá-lo por meio
for line in open(etc):
, mas o python só vai um pouco de cada vez, descartando cada bloco armazenado em buffer após seu processamento.fonte
Eu provavelmente estou estragado por carneiro abundante, mas 15 M não é enorme. Ler para a memória com
readlines()
é o que costumo fazer com arquivos desse tamanho. Acessar uma linha depois disso é trivial.fonte
Estou surpreso que ninguém mencionou islice
ou se você quiser todo o resto do arquivo
ou se você quiser todas as outras linhas do arquivo
fonte
Como não há como determinar o comprimento de todas as linhas sem lê-las, você não tem escolha a não ser iterar todas as linhas antes de sua linha de partida. Tudo que você pode fazer é torná-lo bonito. Se o arquivo for realmente grande, você pode querer usar uma abordagem baseada em gerador:
Nota: o índice é zero com base nesta abordagem.
fonte
Se você não quiser ler o arquivo inteiro na memória, pode ser necessário criar algum formato diferente de texto simples.
é claro que tudo depende do que você está tentando fazer e da frequência com que irá pular pelo arquivo.
Por exemplo, se você for pular para as linhas várias vezes no mesmo arquivo e sabe que o arquivo não muda enquanto trabalha com ele, você pode fazer o seguinte:
Primeiro, passe por todo o arquivo e grave o " procurar-localização "de alguns números de linha-chave (como, sempre 1000 linhas),
então se você quiser a linha 12005, pule para a posição de 12000 (que você gravou) e leia 5 linhas e você saberá está na linha 12005 e assim por diante
fonte
Se você souber com antecedência a posição no arquivo (ao invés do número da linha), você pode usar file.seek () para ir para essa posição.
Edit : você pode usar a função linecache.getline (filename, lineno) , que retornará o conteúdo da linha lineno, mas somente após ler o arquivo inteiro na memória. Bom se você estiver acessando aleatoriamente linhas de dentro do arquivo (como o próprio python pode querer fazer para imprimir um traceback), mas não é bom para um arquivo de 15 MB.
fonte
O que gera o arquivo que você deseja processar? Se for algo sob seu controle, você pode gerar um índice (qual linha está em qual posição.) No momento em que o arquivo é anexado. O arquivo de índice pode ter um tamanho de linha fixo (espaço preenchido ou 0 números preenchidos) e definitivamente será menor. E assim pode ser lido e processado rapidamente.
fonte
Eu tive o mesmo problema (precisa recuperar de uma linha específica de arquivo enorme).
Certamente, posso sempre percorrer todos os registros no arquivo e interrompê-lo quando o contador for igual à linha de destino, mas não funciona de forma eficaz em um caso em que você deseja obter o número plural de linhas específicas. Isso fez com que o problema principal fosse resolvido - como lidar diretamente com o local de arquivo necessário.
Descobri a próxima decisão: primeiro concluí o dicionário com a posição inicial de cada linha (a chave é o número da linha e o valor - comprimento acumulado das linhas anteriores).
em última análise, função de objetivo:
t.seek (line_number) - comando que executa a remoção do arquivo até o início da linha. Então, se você confirmar readline - você obterá sua linha de destino.
Usando essa abordagem, economizei uma parte significativa do tempo.
fonte
Você pode usar o mmap para encontrar o deslocamento das linhas. MMap parece ser a maneira mais rápida de processar um arquivo
exemplo:
então use f.seek (offsets) para mover para a linha que você precisa
fonte
As próprias linhas contêm alguma informação de índice? Se o conteúdo de cada linha fosse algo como "
<line index>:Data
", então aseek()
abordagem poderia ser usada para fazer uma pesquisa binária pelo arquivo, mesmo se a quantidade deData
for variável. Você iria procurar o ponto médio do arquivo, ler uma linha, verificar se seu índice é maior ou menor do que o desejado, etc.Caso contrário, o melhor que você pode fazer é apenas
readlines()
. Se você não quiser ler todos os 15 MB, pode usar osizehint
argumento para pelo menos substituir muitosreadline()
s por um número menor de chamadas parareadlines()
.fonte
Se você está lidando com um arquivo de texto e baseado no sistema Linux , você pode usar os comandos do Linux.
Para mim, funcionou bem!
fonte
Aqui está um exemplo usando 'readlines (sizehint)' para ler um pedaço de linhas por vez. DNS apontou essa solução. Escrevi este exemplo porque os outros exemplos aqui são orientados por linha única.
fonte
Nenhuma das respostas é particularmente satisfatória, então aqui está um pequeno trecho para ajudar.
Exemplo de uso:
Isso envolve fazer muitas buscas de arquivos, mas é útil para os casos em que você não pode colocar o arquivo inteiro na memória. Ele faz uma leitura inicial para obter as localizações das linhas (portanto, ele lê todo o arquivo, mas não o mantém na memória) e, em seguida, cada acesso faz uma busca pelo fato.
Eu ofereço o trecho acima sob a licença MIT ou Apache a critério do usuário.
fonte
Pode usar esta função para retornar a linha n:
fonte