Misturando arquivos e loops
-
05-07-2019 - |
Pergunta
Eu estou escrevendo um script que registra os erros de outro programa e reiniciar o programa de onde parou quando encontra um erro. Por qualquer motivo, os desenvolvedores deste programa não sentem que é necessário para colocar essa funcionalidade em seu programa por padrão.
De qualquer forma, o programa leva um arquivo de entrada, analisa-lo, e cria um arquivo de saída. O arquivo de entrada é em um formato específico:
UI - 26474845
TI - the title (can be any number of lines)
AB - the abstract (can also be any number of lines)
Quando o programa gera um erro, dá-lhe as informações de referência que você precisa para monitorar o erro - ou seja, a interface do usuário, a seção (título ou resumo), e o número da linha em relação ao início do título ou resumo. Quero registrar as frases ofensivas do arquivo de entrada com uma função que leva o número de referência e o arquivo, encontra a sentença, e registra-lo. A melhor maneira que eu poderia pensar em fazer isso envolve a avançar através do arquivo de um número específico de vezes (ou seja, n vezes, onde n é o número da linha em relação ao início do seciton). A maneira que parecia fazer sentido para fazer isso é:
i = 1
while i <= lineNumber:
print original.readline()
i += 1
Eu não vejo como isso iria me tornar os dados perder, mas Python pensa que seria, e diz ValueError: Mixing iteration and read methods would lose data
. Alguém sabe como fazer isso corretamente?
Solução
Você começa a ValueError porque seu código provavelmente tem for line in original:
além original.readline()
. Uma solução fácil que corrige o problema sem fazer seu programa mais lento ou consumir mais memória está mudando
for line in original:
...
para
while True:
line = original.readline()
if not line: break
...
Outras dicas
Assumindo que você só precisa de uma linha, isso poderia ser de ajuda
import itertools
def getline(fobj, line_no):
"Return a (1-based) line from a file object"
return itertools.islice(fobj, line_no-1, line_no).next() # 1-based!
>>> print getline(open("/etc/passwd", "r"), 4)
'adm:x:3:4:adm:/var/adm:/bin/false\n'
Você pode querer erros StopIteration de captura (se o arquivo tem menos linhas).
Aqui está uma versão sem o padrão while True
feio e sem outros módulos:
for line in iter(original.readline, ''):
if …: # to the beginning of the title or abstract
for i in range(lineNumber):
print original.readline(),
break