Открыть файл, прочитать его, обработать и записать обратно - самый короткий метод в 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 делает работу короче, поскольку мне не нужно явно открывать и закрывать файл.

Есть другие идеи?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
13
0
9 851
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Кажется, это работает:

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

Работает здесь только при вызове f.seek(0) после f.truncate(0), в противном случае новый файл начинается с 11 нулевых байтов (Python 2.7.3 в Linux).

scai 07.09.2012 15:14

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

См. Генераторные хитрости для системных программистов Дэвида М. Бизли, который действительно важен для чтения всем, кто пишет такой код.

Отличная ссылка - спасибо! Меня немного беспокоит возросшая сложность отладки конвейеров, но мощность неоспорима.

Kevin Little 23.10.2008 08:09

Разработка через тестирование - ваш друг.

Robert Rossney 23.10.2008 13:00

Если вы ищете 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 в конвейере для создания нового файла:

$ myscript.py infile.txt > outfile.txt

Хотя это мне не очень помогает, так как я хочу записать обратно в тот же файл. И перенаправление не будет работать таким образом для одного и того же файла

Eli Bendersky 23.10.2008 20:16

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

from twisted.python.filepath import FilePath
p = FilePath(filename)
p.setContent(process(p.getContent()))
Ответ принят как подходящий

На самом деле более простой способ использования 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),

Очень хорошо, спасибо, что указали на этот вариант. Вы также можете использовать функцию filelineno () из fileinput, чтобы автоматически получать номер строки, не считая его самостоятельно.

Eli Bendersky 24.10.2008 10:12

Да, и вы забыли запятую после печати - код добавляет лишние символы новой строки :-)

Eli Bendersky 24.10.2008 10:16

Спасибо, что уловили это - я изменил пример.

Hortitude 24.10.2008 20:10

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

# 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()))

Другие вопросы по теме