Как использовать метод write () для файла без замены символов? - PullRequest
0 голосов
/ 24 декабря 2018

У меня есть файл .txt, содержимое которого:

This is an example file.
These are its contents.
This is line 3.

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

f = open(r'C:\Users\piano\Documents\sample.txt', 'r+')
f.seek(0, 0)
f.write('Now I am adding text.\n')

Я ожидаю, что файл будет иметь следующий вид:

Now I am adding text.
This is an example file.
These are its contents.
This is line 3.

... но вместо этого он читает:

Now I am adding text.
.
These are its contents.
This is line 3.

Так почему же часть текста заменяется вместотекст, который я пишу, просто добавляется в начало?Как я могу это исправить?

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Большинство файловых систем не работают так.Содержимое файла сопоставляется с блоками данных, и эти блоки данных не обязательно будут смежными в базовой системе (т.е. не обязательно «бок о бок»).

Когда вы ищете, вы ищетев байтовое смещение.Поэтому, если вы хотите вставить новые данные между 2-байтовыми смещениями определенного блока, вам придется фактически сдвинуть все последующие данные на длину того, что вы вставляете.Поскольку блок может быть полностью «заполнен», сдвиг байтов может потребовать выделения нового блока.Если последующий блок также был полностью «заполнен», вам придется также перенести данные этого блока и т. Д. Вы можете начать понимать, почему не существует «простой» операции для смещения данных.

Как правило, мы решаем эту проблему, просто считывая все данные в память, а затем перезаписывая их обратно в файл.Когда вы сталкиваетесь со смещением байтов, в которое вы заинтересованы вставить «новый» контент, вы записываете свой буфер и затем продолжаете записывать «оригинальные» данные.В Python вам не придется беспокоиться о чередовании нескольких буферов при записи, поскольку Python будет абстрагировать данные в некоторую структуру данных.Таким образом, вы просто объединяете структуры данных более высокого уровня (например, если это текстовый файл, просто объединяете 3 строки).

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


Теперь, если вы рассмотрите «смещение» данных в блоках данных, о которых я упоминал выше, выМожно рассмотреть более простой крайний случай, когда вы вставляете данные длины N со смещением, кратным N, где N - фиксированный размер блока данных в файловой системе.В этом случае, если вы думаете о блоках данных как о связном списке, вы можете считать довольно простой операцией добавить новый блок данных между смещением, в которое вы вставляете, и следующим блоком в списке.

Фактически, системы Linux поддерживают выделение дополнительного блока на этой границе.См fallocate.

0 голосов
/ 24 декабря 2018

Запись - перезапишет любой существующий контент
Чтобы преодолеть это, вы можете сделать:

with open(r'C:\Users\piano\Documents\sample.txt', 'r+') as file:
    string = file.read()
    file.truncate(0) #delete all contents
    file.seek(0, 0)
    file.write('Now I am adding text.\n' + string)

Также рекомендуется использовать with, потому что он поставляется автоматически с методом close() вего __exit__() магический метод.Это важно, так как не все интерпретаторы Python используют CPython

Бонус: если вы хотите вставить промежуточные строки, вы можете сделать:

with open(r'C:\Users\piano\Documents\sample.txt', 'r+') as file:
    contents = file.readlines()
    contents.insert(1, 'Now I am adding text.\n') 
    #Inserting into second line
    file.truncate(0) #delete all contents
    file.seek(0, 0)
    file.writelines(contents)
...