Как правильно изменять файлы в Python: техники и код
Основной подход: чтение, изменение, запись
Наиболее универсальный способ редактирования файла в Python состоит из трех шагов: открыть файл в режиме чтения ('r'), прочитать все содержимое, внести изменения в строку или байты, затем открыть тот же файл в режиме записи ('w') и записать новое содержимое. Этот метод подходит для файлов любого объема, если данные полностью помещаются в оперативную память.
with open('example.txt', 'r', encoding='utf-8') as f:
text = f.read()
text = text.replace('старая_строка', 'новая_строка')
with open('example.txt', 'w', encoding='utf-8') as f:
f.write(text)
ввод программ на python (ввод данных в программе python)
В примере заменяется одна подстрока на другую. Кодировка указана явно - это позволяет избежать проблем с кириллицей. Если файл очень большой (сотни мегабайт), читать его целиком неэффективно; в таких случаях применяется построчная обработка с записью во временный файл (см. варианты ниже).
Возможные проблемы:
- Потеря данных при сбое во время записи: если процесс прервется, исходный файл может оказаться пустым. Решение: записывать сначала во временный файл, затем заменять оригинал.
- Неверная кодировка: использование encoding помогает, но если файл уже открыт в другой кодировке, возникнут ошибки UnicodeDecodeError. Нужно определить кодировку заранее (например, через chardet).
- Случайная перезапись: режим 'w' обнуляет файл. Если нужно дописать или изменить часть, используйте другие варианты.
Различные варианты редактирования
Как добавить текст в конец файла?
Используется режим 'a' (append). Файл открывается для добавления данных в конец, указатель ставится на последнюю позицию.
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('Новая запись\n')
Python file io (ввод-вывод файлов в python)
Типичная ошибка: забыть символ новой строки - каждая запись окажется на одной строке. Кодировка должна совпадать с уже имеющейся в файле.
Как вставить строку в середину файла, не перезаписывая его полностью?
Прямой вставки без временного файла не существует. Приходится читать все строки, вставлять нужную и записывать заново.
with open('data.txt', 'r', encoding='utf-8') as f:
lines = f.readlines()
lines.insert(2, 'Вставленная строка\n') # вставить после строки с индексом 1
with open('data.txt', 'w', encoding='utf-8') as f:
f.writelines(lines)
Python temp files (временные файлы в python)
Проблема: при большом количестве строк список lines занимает много памяти. Решение - использовать модуль fileinput (см. примеры ниже).
Как заменить все вхождения слова в файле?
Простой способ - использовать метод str.replace() для всего текста.
with open('text.txt', 'r', encoding='utf-8') as f:
content = f.read()
content = content.replace('Python', 'Java')
with open('text.txt', 'w', encoding='utf-8') as f:
f.write(content)
Python index files (индексация файлов в python)
Замена регистрозависимая. Для регистронезависимой замены потребуется регулярное выражение или предварительный поиск. Также метод replace не работает с шаблонами - только с фиксированными строками.
Как изменить файл без создания временного файла, используя режим 'r+'?
Режим 'r+' позволяет читать и писать, но запись начинается с текущей позиции указателя, что может привести к наложению данных. Для замены одинаковой длины это подходит, для разной - нет.
with open('test.bin', 'r+b') as f:
data = f.read()
# заменить байты той же длины
data = data.replace(b'old', b'new')
f.seek(0)
f.write(data)
f.truncate()
File python class (класс для работы с файлами в python)
Ошибки: неверное позиционирование указателя; забытый вызов truncate(), если новые данные короче старых - в конце останется мусор.
Как редактировать бинарные файлы (например, изображения)?
Открывать в режиме 'rb+', изменять конкретные байты, зная их смещение. Часто используется модуль struct для упаковки/распаковки чисел.
import struct
with open('data.bin', 'r+b') as f:
f.seek(4) # смещение 4 байта
value = struct.unpack('i', f.read(4))[0]
value += 1
f.seek(4)
f.write(struct.pack('i', value))
Сложность: нужно точно знать формат данных, иначе можно повредить файл. Для сложных форматов лучше использовать специализированные библиотеки.
Расширенные примеры с пояснениями
1. Замена нескольких строк с помощью временного файла (безопасный способ)
import tempfile
import shutil
source = 'large_file.txt'
temp = tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8')
with open(source, 'r', encoding='utf-8') as inf:
for line in inf:
if 'привет' in line:
line = line.replace('привет', 'здравствуйте')
temp.write(line)
temp.close()
shutil.move(temp.name, source)
Пояснение: файл обрабатывается построчно, поэтому память не перегружается. Временный файл создается в системной папке, после обработки заменяет оригинал. Если во время работы возникнет ошибка, исходный файл останется нетронутым (временный будет удален автоматически).
Файл large_file.txt будет изменен, но только после успешного завершения скрипта.
2. Использование модуля fileinput для редактирования «на месте»
import fileinput
for line in fileinput.input('config.ini', inplace=True, encoding='utf-8'):
print(line.replace('DEBUG', 'INFO'), end='')
Пояснение: fileinput перенаправляет стандартный вывод в файл. Каждая строка выводится через print (по умолчанию добавляет перевод строки; end='' отключает его). Параметр inplace=True заставляет модуль создавать резервную копию (если нужно, можно задать суффикс.
Файл config.ini будет изменен без создания временного файла вручную. Старая версия сохраняется с расширением .bak (если не указан параметр backup).
3. Редактирование с помощью pathlib (для простых замен)
from pathlib import Path
file = Path('notes.txt')
text = file.read_text(encoding='utf-8')
text = text.replace('неправильно', 'правильно')
file.write_text(text, encoding='utf-8')
Пояснение: методы read_text() и write_text() скрывают открытие/закрытие файла. Удобно для небольших файлов. Аналогично для бинарных: read_bytes() и write_bytes().
Файл notes.txt будет перезаписан.
4. Замена с помощью регулярных выражений (гибкая замена)
import re
with open('mixed.txt', 'r', encoding='utf-8') as f:
content = f.read()
pattern = r'\b(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\b' # IP-адрес
replacement = r'\1-\2-\3-\4'
new_content = re.sub(pattern, replacement, content)
with open('mixed.txt', 'w', encoding='utf-8') as f:
f.write(new_content)
Пояснение: регулярное выражение ищет все IP-адреса и заменяет точки на дефисы. re.sub обрабатывает весь текст. Важно экранировать обратные ссылки в строке замены.
Пример: '192.168.0.1' станет '192-168-0-1'.
5. Редактирование CSV-файла (изменение столбцов)
import csv
rows = []
with open('data.csv', 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
row['age'] = str(int(row['age']) + 1) # увеличить возраст на 1
rows.append(row)
with open('data.csv', 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=reader.fieldnames)
writer.writeheader()
writer.writerows(rows)
Пояснение: DictReader преобразует строки в словари по заголовкам. Изменяем нужное поле, затем записываем все строки обратно. Модуль csv автоматически обрабатывает кавычки и разделители.
Возраст каждого человека увеличится на 1. Файл перезаписан.
6. Вставка строки после определенного маркера
marker = '# END'
insert_line = 'Новый параметр = значение\n'
with open('settings.ini', 'r', encoding='utf-8') as f:
lines = f.readlines()
for i, line in enumerate(lines):
if line.strip() == marker:
lines.insert(i+1, insert_line)
break
with open('settings.ini', 'w', encoding='utf-8') as f:
f.writelines(lines)
Пояснение: ищется строка, совпадающая с маркером, после нее вставляется новая строка. Если маркер не найден, файл останется без изменений (для надежности можно добавить проверку).
В файл settings.ini после строки '# END' добавится новая строка.