Я пытаюсь обработать JSON-декодирование путем резервного копирования искаженного файла в случае сбоя декодирования, но я испытываю странное поведение, которого я не ожидал от метода os.path.join.

Следующий код завершается с ошибкой: PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'file.txt' -> 'file.txt\\.bak'

file_path = "file.txt"

try:
    with open(file_path, 'r') as f:
        json.load(f)

except json.JSONDecodeError as e:
    os.rename(file_path, os.path.join(file_path, '.bak'))

Если я изменю аргумент следующим образом: os.rename(file_path, file_path + '.bak') Код выполняется, как и ожидалось, без ошибки разрешения. Похоже, что метод os.path.join фактически обращается к файлу, а не является строгой строковой операцией. Это ожидаемое поведение?

0
Alex 13 Май 2019 в 18:20

2 ответа

Лучший ответ

os.path.join(file_path, '.bak')) на самом деле даст вам file.txt\\.bak, как вы видите в коде ошибки, но file_path + '.bak' даст вам правильное имя файла file.txt.bak

os.path.join добавляет разделитель между его аргументами, следовательно, он заканчивает тем, что добавил этот разделитель и в вашем случае

Например, в MacOS вы можете увидеть, что он добавляет разделитель между каждым из своих аргументов. os.path.join более полезен для добавления имен каталогов, полного имени файла с путями к каталогам.

In [4]: import os                                                                                                                                                                 

In [5]: os.path.join('filename','.bak')                                                                                                                                           
Out[5]: 'filename/.bak'

In [6]: os.path.join('folder1', 'folder2')                                                                                                                                        
Out[6]: 'folder1/folder2'

Ошибка возникает из-за того, что ОС Windows пытается создать файл .bak в папке с именем file.txt, что невозможно, поскольку файл file.txt представляет собой обычный файл, а не каталог, что является правильным.

Использование file_path+'.bak правильно создает file.path.bak в нужной папке, поэтому вы не увидите там ошибки!

1
martineau 13 Май 2019 в 15:37

Сообщение об ошибке - это ключ. Как обычно в Windows причина ( потому что он используется другим процессом ) неверна, но имена ( 'file.txt' -> 'file.txt \ .bak' ) верны.

Присоединение не является конкатенацией строк, но предполагает, что все члены пути, кроме последнего, представляют папки. Итак, здесь вы пытаетесь создать файл .bak в папке с именем file.txt. Это невозможно, потому что file.txt - простой файл, а не каталог.

С другой стороны, когда вы используете os.rename(file_path, file_path + '.bak'), вы переименовываете file.txt в file.txt.bak в той же папке, что разрешено базовой файловой системой, поэтому ошибка отсутствует.

Таким образом, поведение соответствует ожидаемому, за исключением начала сообщения об ошибке.


Поскольку я не являюсь ядром Microsoft Developper, следующее предположение является диким. Количество ошибок, указанных системой, ограничено. Функция переименования C получила 2 строки и передала их системному вызову для переименования. Как и ожидалось, файловая система вызвала ошибку, но так как она не была ни физической, ни полной ошибкой файловой системы, она просто выбрала причину отказано в разрешении . Что на самом деле не так, потому что нельзя создавать папки в виде простого файла. Но сообщение об этой ошибке, к сожалению, , потому что оно используется другим процессом , что здесь глупо

1
Serge Ballesta 13 Май 2019 в 15:39