Как заменить строчку в .txt файле через python 3?

sm0ker71

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

3 ответа

sm0ker71

Замену можно сделать так:

with open ('test.txt', 'r') as f: old_data = f.read()
new_data = old_data.replace('что_меняем', 'на_что_меняем')
with open ('test.txt', 'w') as f: f.write(new_data)


sm0ker71

Если длина новой строки не совпадает с длиной старой, то придётся переписать весь файл (начиная со строчки, которую вы хотите заменить) даже если вам надо заменить только одну строку в файле (за редкими исключениями). Связанный вопрос: Запись текстовой строки по нужному индексу в файл на языке Си?

Чтобы в случае ошибки сохранить оригинал или для больших файлов (когда всё содержимое в памяти не помещается), может использоваться временный файл куда новое содержимое пишется и в конце в случае успеха он переименовывается в исходное имя файла. Похожий подход использует fileinput стандартный модуль: исходный файл переименовывается (чтобы из него читать текущее содержимое), а стандартный вывод перенаправляется в указанный файл (простой print печатает прямо в файл):

#!/usr/bin/env python3
import fileinput
import os
with fileinput.FileInput('файл.txt', inplace=True, backup='.bak') as file: for line file: line = line.rstrip() # remove trailing (invisible) space print('новое' if line == 'старое' else line) # stdout is redirected to the file
os.unlink(filename + '.bak') # remove the backup on success

Можно самостоятельно явно временный файл создать:

#!/usr/bin/env python3
from pathlib import Path
from tempfile import NamedTemporaryFile
path = Path('файл.txt')
with path.open() as file, \ NamedTemporaryFile('w', dir=str(path.parent), delete=False) as output_file: for line in file: line = line.rstrip() print('новое' if line == 'старое' else line, file=output_file)
Path(output_file.name).replace(path) # replace the input file on success

Отличие в том, что оригинальное содержимое хранится в .bak файле в fileinput подходе, а в коде с NamedTemporaryFile исходный файл заменяется только в случае успеха (в отсутствии исключений).

Небольшой файл можно в память целиком загрузить, чтобы получить список строк, изменить нужные и целиком перезаписать этот файл, рискуя потерять данные если ошибка возникнет при записи (аналогично коду в @stxdtm ответе):

#!/usr/bin/env python3
filename = 'файл.txt'
with open(filename) as file: lines = ['новое\n' if line.rstrip() == 'старое' else line for line in file]
with open(filename, 'w') as file: file.writelines(lines)

Подробнее представленные подходы можно по ссылкам в похожем ответе посмотреть.

Если длина новой строки совпадает с длиной старой (в байтах), то можно прямо по месту изменения делать не переписывая другие части файла, к примеру, используя mmap модуль, который позволяет файл рассматривать и как файл (.readline(), etc) и как байтовую строку (.find(), можно применять регулярные выражения). Связанный вопрос: Python - How can I change bytes in a file.


sm0ker71

Открыть файл на чтение можно либо так

file = open('filename.txt', 'r')
firstline = file.readlines()[0].strip()
file.close()

Либо так:

with open('filename.txt', 'r') as f: print('first line', f.readlines()[0].strip())

Преимущество второго способа в том, что вам не надо закрывать файл вручную. Конструкция withсделает это за вас после закрытия её блока.

Перезаписать файл можно же таким образом:

with open('filename.txt', 'r') as f1, open('filename1.txt', 'w') as f2: f2.write(f1.read())

Но так как вы хотите писать файл с заменой строки, то вам нужно воспользоваться перебором по readlines() и либо регулярными выражениями, либо сравнением текущей строки с той, которую вы ищите (если у вас есть искомая строка, конечно) и её заменой.

Грубо говоря, вы можете сделать это как-то так:

with open('filename.txt', 'r') as f1, open('filename1.txt', 'w') as f2: lines = f1.readlines() for line in lines: line = line.strip() if line == 'искомая строка': f2.write('новая строка\n') else: f2.write(line)

Также могут помочь функции startswith() и endswith(), если у вас есть только начало или конец от искомой строки. И помните про регистр!

Также можно не перебирать строки, а обратиться к строке по индексу, если вам известно какой у неё номер, и заменить её содержание.

И можно воспользоваться функцией replace(), как уже написал автор второго ответа, что сократит количество кода, но заменит абсолютно все вхождения. Чтобы этого избежать, при вызове функции можно указать максимальное число совершаемых замен: S.max(sub_in_str, to_change_str, max).

Также учитывайте, что replace() совершит замену даже если строка частично совпадает. То есть выполнив это:

'This is a simple example'.replace('is', 'was')

Мы получим Thwas was a simple example

licensed under cc by-sa 3.0 with attribution.