чтение и запись в файл python добавляет неожиданные символы при прерывании работы скрипта - PullRequest
0 голосов
/ 07 апреля 2019

Вот моя проблема, у меня есть сценарий, который имеет много шагов, в основном он открывает файл, читает его и после прочтения записывает обратно в файл.Все хорошо, когда сценарий завершается.Проблемы возникают, когда происходит исключение сортировок или сценарий прерывается.Я открываю файл в режиме «r +», потому что, если я открываю его в режиме «w», файл сразу становится пустым, а если сценарий прерывается, он остается пустым, в то время как я хочу сохранить прежнее значение.Ниже приведен пример, но не точный сценарий, который я выполняю. Если сценарий прерывается (или возникает исключение, даже если он обрабатывается), значение внутри test.txt будет «myVar = 13e» или «myVar = 13ne»,Не всегда, но часто.Почему это происходит и как этого избежать?

import time
from test import myVar
file_path = "./test.py"
with open(file_path, 'r+', encoding=‘utf-8’) as f:
    # read the file content which is for example “myVar=11”
    # do calculations with myVar
    #str_to_oc = "myVar="+str(row[0]) #row[0] is fetched from database, it’s ID of the record. It’s an integer
    str_to_oc = “myVar=“+str(13) # I hardcoded the 13 value here instead of the database row[0]
    time.sleep(3) #just adding a delay so you can interrupt easily
    # write back a string “myVar=13” which is he new value of 13
    f.write(str_to_oc)

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

Ответы [ 3 ]

0 голосов
/ 08 апреля 2019

Вы видите эффект буферизации.

Вы можете уменьшить эффект, подключившись к вызову flush :

    f.write(str_to_oc)
    f.flush()

CTRL / C прибывает асинхронно,так что это не исправит это полностью.Кроме того, если вы решите вставить / удалить, чтобы отдельные записи и общий размер файла изменились, вы будете недовольны тем, как старые + новые записи смещены.

За кулисами иногда io.BufferedWriterзапрос необработанной записи , которая превращается в уровень ОС syscall .Вы говорите, что CTRL / C или трассировка фатального стека приводит к преждевременному завершению программы.В этом случае весь процесс интерпретатора Python завершается, вызывая неявное close(), что может привести к комбинации старых + новых байтов, считываемых из вашего файла.Обратите внимание, что многобайтовая кодовая точка UTF8 может охватывать дисковые блоки, что может привести к несчастью.

Учитывая наблюдаемую надежность вашей программы, звучит так, что вам будет хорошо оставить исходную нетронутой до успешного завершения обработки:

tmp_path = file_path + '.tmp'
with open(file_path) as fin:
    with open(tmp_path, 'w') as fout:
        for line in fin:
            # (do stuff, compute output)
            fout.write(out_line + '\n')

os.rename(tmp_path, file_path)  # atomic operation, all-or-nothing
0 голосов
/ 08 апреля 2019

Просто для тех, кто заинтересован, я сделал хакерскую вещь и добавил комментарий к строке, которую я записал в файл.

str_to_oc = “myVar=“+str(13)+”#”
0 голосов
/ 08 апреля 2019

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

...