Python os.makedirs и Shutil.copyfile — Ошибка 13 — Отказано в доступе

В моем коде я создаю каталог следующим образом:

try:
    os.makedirs(playlist_name)
except OSError as e:
    if e.errno != errno.EEXIST:
        raise

Что создает каталог в том месте, где я запускаю свой скрипт Python. Затем я хочу скопировать три файла из исходного каталога, где находится папка, во вновь созданный каталог, например

# Copy FFMPEG files into that folder so youtube dl can download the videos as audio tracks
# Tried using os.getcwd() to get full path, same error
shutil.copyfile(os.getcwd() + '\\ffmpeg.exe', os.getcwd() + "\\" + playlist_name)
shutil.copyfile('ffplay.exe', "/" + playlist_name + "/")
shutil.copyfile('ffprobe.exe', "/" + playlist_name + "/")

Однако попытка скопировать эти файлы вызывает эту ошибку:

PermissionError: [Errno 13] Permission denied: 'C:\\Users\\ME\\Documents\\python\\DIRECTORY\\PLAYLIST_NAME_HERE'

Я пробовал различные методы копирования Shutil с той же ошибкой.

РЕДАКТИРОВАТЬ: это работает на окнах


person Cambray    schedule 01.12.2017    source источник
comment
Ошибка сообщает вам, в чем проблема, убедитесь, что у вас есть разрешения с учетной записью, которая выполняет ваш скрипт, возможно, вашим пользователем.   -  person user1767754    schedule 01.12.2017
comment
@ user1767754: На самом деле это не ошибка разрешений в классической модели, есть ли у вас разрешение на запись; Windows использует этот код ошибки (или EPERM в других случаях, но все же Python PermissionError), когда вы пытаетесь перезаписать каталог файлом или открыть каталог для записи, как если бы это был файл, проблема в этом случае, потому что вы повторно не разрешено делать это. EISDIR (Python IsADirectoryError) — это то, что вы ожидаете, но Windows использует EACCES/EPERM, потому что они так вас ненавидят.   -  person ShadowRanger    schedule 01.12.2017


Ответы (1)


Согласно в copyfile документах:

dst должно быть полным именем целевого файла; посмотрите на shutil.copy() для копии, которая принимает путь к целевому каталогу.

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

for filename in ('ffmpeg.exe', 'ffplay.exe', 'ffprobe.exe'):
    shutil.copyfile(filename, os.path.join(playlist_name, filename))

Проблема была бы более очевидной в UNIX-подобной системе, потому что эти системы отклонили бы действие с EISDIR, что вызвало бы вызов Python IsADirectoryError, но Windows по какой-то причине предпочла использовать более общие коды ошибок, связанные с проблемами разрешений/доступа ( EACCES и связанные с ними коды ошибок Windows), которые Python переводит в PermissionError (потому что Windows просто не говорит ему о реальной проблеме, и это приведет к всевозможным условиям гонки, если Python попытается проверить, действительно ли проблема заключается в попытке использовать каталог в виде файла для исправления типа исключения).

person ShadowRanger    schedule 01.12.2017
comment
Системный вызов NtCreateFile возвращает STATUS_FILE_IS_A_DIRECTORY. Проблема в том, что Windows сопоставляет это значение состояния с кодом ошибки ERROR_ACCESS_DENIED, что является унаследованным поведением с древних времен (16-разрядная Windows). Если бы он явно гарантировал сохранение последнего значения состояния NT потока, тогда Python мог бы просто вызвать RtlGetLastNtStatus, чтобы иметь возможность повысить IsADirectoryError в этом случае. - person Eryk Sun; 01.12.2017
comment
Теперь я вижу, где я ошибался, имеет смысл, что мне не понравилось, что я пытался заменить каталог файлом. Хорошая петля тоже, прошлой ночью было поздно, и я потерял весь ход мыслей. Спасибо. - person Cambray; 01.12.2017