Я получаю WinError 32 и Errno 13 при попытке переместить файл с помощью shutil.move

#python #windows

#python #Windows

Вопрос:

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

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:/Users/username/Desktop/Python/download_manager/test/20200728_184438000_iOS.MOV' -> 'C:/Users/username/Desktop/Python/download_manager/test2/20200728_184438000_iOS.MOV'

и

PermissionError: [Errno 13] Permission denied: 'C:/Users/username/Desktop/Python/download_manager/test/20200728_184438000_iOS.MOV'

Вот мой код:

 from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


import os 
import json 
import time
import shutil

class Handler(FileSystemEventHandler):
    def on_modified(self, event):
        for filename in os.listdir(folder_to_track):
            src = folder_to_track   "/"   filename
            new_destination = folder_destination   "/"   filename
            print ('moving {} to {}'.format(src,new_destination))
            shutil.move(src, new_destination)


folder_to_track = "C:/Users/olivi/Desktop/Python/download_manager/test"
folder_destination = "C:/Users/olivi/Desktop/Python/download_manager/test2"
event_handler = Handler()
observer = Observer()
observer.schedule(event_handler, folder_to_track, recursive=True)
observer.start()

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    observer.stop()
observer.join()
  

Редактировать:

Я внес следующие изменения, и, похоже, теперь он работает более надежно (хотя иногда он все еще выводит из себя …):

 from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


import os 
import json 
import time
import shutil
import logging

logging.basicConfig(filename="logs.txt", filemode='w', level=logging.INFO, format='%(asctime)-15s %(message)s', datefmt='%Y/%d/%m %H:%M:%S')

class Handler(FileSystemEventHandler):
    def on_modified(self, event):        
        for filename in os.listdir(folder_to_track):
            while True:
                src = folder_to_track   "/"   filename
                new_destination = folder_destination   "/"   filename
                try:
                    shutil.move(src, new_destination)
                    logging.info('moved {} to {}'.format(src, new_destination))
                except PermissionError:
                    continue
                break
            
                
folder_to_track = "C:/Users/olivi/Downloads"
folder_destination = "C:/Users/olivi/Desktop/Python/download_manager/test"
event_handler = Handler()
observer = Observer()
observer.schedule(event_handler, folder_to_track, recursive=True)
observer.start()
logging.info('--Service Started--')

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    observer.stop()
    logging.warning(KeyboardInterrupt)
observer.join()
  

Комментарии:

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

2. Если это не сработает, возможно, os.listdir файл заблокирован. Попробуйте сначала прочитать имена файлов в списке.

3. Единственное, чего я не понимаю, это почему иногда это работает отлично, а иногда нет…

4. Если folder_to_track и folder_destination находятся в одной файловой системе, то shutil.move можно использовать os.rename . Для этого требуется открыть src файл с доступом к удалению (переименованию), который, по-видимому, не используется совместно с открытыми в данный момент ссылками на файл, что приводит к ERROR_SHARING_VIOLATION (32). shutil.move выполняется возврат к копированию и удалению файла. Для копирования требуется открытие с доступом для чтения, что также, вероятно, приводит к сбою из-за нарушения общего доступа, но open , в отличие os.rename , вызывает исключение только для generic EACCES (13), теряя конкретный код ошибки Windows (32).

5. Вероятно, это состояние гонки, для которого простейшим решением является повторная попытка несколько раз в цикле с увеличивающимся временем ожидания.