Открыть файл, прочитать его, обработать и написать обратно - самый короткий метод в Python

Я хочу сделать базовую фильтрацию в файле. Прочтите его, обработайте, запишите.

Я не ищу "гольф", но хочу простейший и элегантный способ добиться этого. Я придумал:

from __future__ import with_statement

filename = "..." # or sys.argv...

with open(filename) as f:
    new_txt = # ...some translation of f.read() 

open(filename, 'w').write(new_txt)

Оператор with делает вещи короче, так как мне не нужно явно открывать и закрывать файл.

Любые другие идеи?

Ответы

Ответ 1

На самом деле проще использовать fileinput, чтобы использовать параметр inplace:

import fileinput
for line in fileinput.input (filenameToProcess, inplace=1):
    process (line)

Если вы используете параметр inplace, он перенаправляет stdout в ваш файл, так что, если вы сделаете печать, он будет записывать обратно в ваш файл.

В этом примере добавляются номера строк в файл:

import fileinput

for line in fileinput.input ("b.txt",inplace=1):
    print "%d: %s" % (fileinput.lineno(),line),

Ответ 2

Я пошла бы на элегантность по-другому: реализовав операции чтения и фильтрации файлов в качестве генераторов, вы напишете больше строк кода, но это будет более гибкий, поддерживаемый и исполняемый код.

См. David M. Beazley Генераторные трюки для системных программистов, что очень важно для тех, кто пишет этот код для чтения.

Ответ 3

Это работает:

with open(filename, "r+") as f:
    new_txt = process(f.read())
    f.truncate(0)
    f.write(new_txt)

Ответ 4

Если вы ищете эквивалент python "perl -pi", здесь довольно хороший:

import fileinput
for line in fileinput.input():
   # process line

Подробнее см. http://www.python.org/doc/2.5.2/lib/module-fileinput.html.

Сделано так, вы использовали бы свой python script в трубе для создания нового файла:

$ myscript.py infile.txt > outfile.txt

Ответ 5

Чтобы сделать это так, чтобы съесть ваши данные, если вы потерпите крах посередине:

from twisted.python.filepath import FilePath
p = FilePath(filename)
p.setContent(process(p.getContent()))

Ответ 6

Мое уродливое (но короткое, как указано в вопросе) решение с выражения генератора;

# Some setup first
file('test.txt', 'w').write('\n'.join('%05d' % i for i in range(100)))


# This is the filter function
def f(i):
    return i % 3


# This is the main part 
file('test2.txt', 'w').write('\n'.join(str(f(int(l))) for l in file('test.txt', 'r').readlines()))


# And a wrapper for sanity
def filter_file(infile, outfile, filter_function)
    outfile.write('\n'.join(filter_function(l) for l in infile.readlines()))