python shutil.move只复制文件而不移动(或删除原始文件),权限错误

zphenhs4  于 2023-01-16  发布在  Python
关注(0)|答案(2)|浏览(311)

我用python编写了一些代码,可以将照片从一个文件夹移动到另一个文件夹,并根据拍摄日期对照片进行排序,但是脚本似乎只是复制文件(或者至少复制时不删除原始文件)。
这是一个权限错误,但我已经尝试了一切我能想到的-运行VSC作为管理员,改变了文件夹的权限,以确保他们是“完全控制”;我确保没有'只读'位。我已经改变了照片和改变文件夹,但它是一回事。
我对python还很陌生,所以有可能是脚本的问题,但是有人能帮忙吗?

import os
import shutil
import exifread
import datetime
import sys
import time
import datetime
 
# Set the source directory path
source_path = os.path.join('D:', 'Test new')
dest_path = os.path.join('F:', 'Test new')
photo_extensions = ['.jpg', 'bmp', '.png', '.raw', '.jpeg','.heic','.gif']
 
def read_source_directory_recursive(directory_path, num_calls=0, max_recursive_calls=1000):
    # If the function has been called more than the maximum number of times, return early
    if num_calls > max_recursive_calls:
        return
    # Read the directory and get a list of files
    files = os.listdir(directory_path)
    # Initialize the variable that keeps track of the number of photos processed
    num_photos_processed = 0
    # Loop through the files
    for dir_name in files:
        file_name = dir_name
        # If the file is a photo based on the extension
        if any(file_name.lower().endswith(ext) for ext in photo_extensions):
            # Get the absolute path of the photo
            photo_path = os.path.join(directory_path, file_name)
 
            # Open image file for reading (binary mode)
            with open(photo_path, 'rb') as f:
                tags = exifread.process_file(f)
                # Get the date the photo was taken
                try:
                    date_taken = tags["EXIF DateTimeOriginal"]
                    date_taken = datetime.datetime.strptime(str(date_taken), '%Y:%m:%d %H:%M:%S')
                except KeyError:
                    date_taken = datetime.datetime.fromtimestamp(os.path.getmtime(photo_path))
 
                year = date_taken.year
                month = date_taken.month
                # Create the destination folder
                dest_folder = os.path.join(dest_path, f"{year}-{month:02d}")
                # Create the destination folder if it does not already exist
                if not os.path.exists(dest_folder):
                    os.mkdir(dest_folder)
                # Create the new file name
                new_file_name = os.path.basename(photo_path)
                if os.path.exists(os.path.join(dest_folder, os.path.basename(photo_path))):
                                        new_file_name = f"{os.path.basename(photo_path).split('.')[0]}_{int(time.time())}.{os.path.basename(photo_path).split('.')[-1]}"
                # Move the photo to the destination folder
                try:
                    shutil.move(photo_path, os.path.join(dest_folder, new_file_name))
                except:
                    # Handle any errors that occur while moving the photo
                    print(f'An error occurred: {sys.exc_info()[0]}')
                # Log a message to indicate that the photo has been moved
                print(f"{photo_path} has been moved to {os.path.join(dest_folder, new_file_name)}")
                num_photos_processed += 1
        # If the file is a directory
        if os.path.isdir(os.path.join(directory_path, dir_name)):
            # Get the absolute path of the directory
            current_directory_path = os.path.join(directory_path, dir_name)
            # Read the directory
            if current_directory_path == source_path:
                return
            try:
                num_photos_processed += read_source_directory_recursive(current_directory_path, num_calls + 1, max_recursive_calls)
            except:
                # Handle any errors that occur while reading the directory recursively
                print(f'An error occurred: {sys.exc_info()[0]}')
    print(f"{num_photos_processed} photos were processed.")
    return num_photos_processed
 
# Call the read_source_directory_recursive function to process the files in the source directory
# Set the maximum number of recursive calls to 2000
read_source_directory_recursive(source_path, 0, 2000)

以下是完整的追溯:

Traceback (most recent call last):
  File "C:\Python311\Lib\shutil.py", line 825, in move
    os.rename(src, real_dst)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'D:Test\\(1).JPG' -> 'D:Test 2\\2015-05\\(1).JPG'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Ed\Documents\Code\organise_photos.py", line 54, in read_source_directory_recursive
    shutil.move(photo_path, os.path.join(dest_folder, new_file_name))
  File "C:\Python311\Lib\shutil.py", line 846, in move
    os.unlink(src)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'D:Test\\(1).JPG'
Traceback (most recent call last):
  File "C:\Users\Ed\Documents\Code\organise_photos.py", line 77, in <module>
    read_source_directory_recursive(source_path, 0, 1)
  File "C:\Users\Ed\Documents\Code\organise_photos.py", line 59, in read_source_directory_recursive
    print(f'An error occurred: {e}')
                                ^
UnboundLocalError: cannot access local variable 'e' where it is not associated with a value
3qpi33ja

3qpi33ja1#

如上所述,问题是文件的关闭。一个干净的处理方法是用with语句获取标签,并将其余代码作为with语句的同级缩进级别:

# Open image file for reading (binary mode)
    with open(photo_path, 'rb') as f:
        tags = exifread.process_file(f)
    # Get the date the photo was taken
    try:
        date_taken = tags["EXIF DateTimeOriginal"]
        date_taken = datetime.datetime.strptime(str(date_taken), '%Y:%m:%d %H:%M:%S')
     except KeyError:
        date_taken = datetime.datetime.fromtimestamp(os.path.getmtime(photo_path))
     ...
3xiyfsfu

3xiyfsfu2#

感谢@qouify,他在上面的评论中提出了这个建议,但是,文件仍然处于“读取”状态,所以不能同时删除。为了解决这个问题,我不得不关闭正在阅读文件的with语句。完整的代码如下所示:
编辑:我还取出了HEIC文件,因为它们不适用于此代码。根据@LhasaDad的回复对代码进行了更改-谢谢!

import os
import shutil
import exifread
import datetime
import sys
import time

# Set the source directory path
source_path = os.path.join('D:', 'Test 2')
dest_path = os.path.join('D:', 'Test')
photo_extensions = ['.jpg', 'bmp', '.png', '.raw', '.jpeg']
 
def read_source_directory_recursive(directory_path, num_calls=0, max_recursive_calls=1000):
    # If the function has been called more than the maximum number of times, return early
    if num_calls > max_recursive_calls:
        return
    # Read the directory and get a list of files
    files = os.listdir(directory_path)
    # Initialize the variable that keeps track of the number of photos processed
    num_photos_processed = 0
    # Loop through the files
    for dir_name in files:
        file_name = dir_name
        # If the file is a photo based on the extension
        if any(file_name.lower().endswith(ext) for ext in photo_extensions):
            # Get the absolute path of the photo
            photo_path = os.path.join(directory_path, file_name)
 
            # Open image file for reading (binary mode)
            with open(photo_path, 'rb') as f:
                tags = exifread.process_file(f)
                #f.close()
            # Get the date the photo was taken
            try:
                date_taken = tags["EXIF DateTimeOriginal"]
                date_taken = datetime.datetime.strptime(str(date_taken), '%Y:%m:%d %H:%M:%S')
            except KeyError:
                    date_taken = datetime.datetime.fromtimestamp(os.path.getmtime(photo_path))
            year = date_taken.year
            month = date_taken.month
            # Create the destination folder
            dest_folder = os.path.join(dest_path, f"{year}-{month:02d}")
                # Create the destination folder if it does not already exist
            if not os.path.exists(dest_folder):
                os.mkdir(dest_folder)
            # Create the new file name
            new_file_name = os.path.basename(photo_path)
            if os.path.exists(os.path.join(dest_folder, os.path.basename(photo_path))):
                                    new_file_name = f"{os.path.basename(photo_path).split('.')[0]}_{int(time.time())}.{os.path.basename(photo_path).split('.')[-1]}"
            # Move the photo to the destination folder
            try:
                shutil.move(photo_path, os.path.join(dest_folder, new_file_name))
            except:
                    # Handle any errors that occur while moving the photo
                print(f'An error occurred: {sys.exc_info()[0]}')
            # Log a message to indicate that the photo has been moved
            print(f"{photo_path} has been moved to {os.path.join(dest_folder, new_file_name)}")
            num_photos_processed += 1
        # If the file is a directory
        if os.path.isdir(os.path.join(directory_path, dir_name)):
            # Get the absolute path of the directory
            current_directory_path = os.path.join(directory_path, dir_name)
            # Recursively call the function to process the contents of the directory
            read_source_directory_recursive(current_directory_path, num_calls + 1)
    return num_photos_processed
 
# Call the function to process the contents of the source directory
num_photos_processed = read_source_directory_recursive(source_path)
# Print the number of photos processed
print(f"{num_photos_processed} photos have been processed.")

相关问题