Python删除文件 - "目前正被其他进程使用"

时间:2015-08-10 04:36:07

标签: python image file-handling

要求

我必须尝试创建一个程序来删除所有损坏的图像(以及小于400x400的图像),并将其余图像过滤为10,000个组。

问题

目前,当我尝试删除任何"损坏"它表示该文件目前正由以下错误的另一个进程使用:

  

该进程无法访问该文件,因为该文件正由另一个进程使用。

采取的步骤

我尝试了多种方法来自由设置文件,包括使用"后踏板"应用程序移动到下一个图像然后返回踏板尝试删除那个但仍然保持打开的策略。 如果我尝试在Python打开时手动删除图像,那么很愉快。

请参阅以下代码:

def confirmIt():
#======== Confirm Selection and Move files to new sub-directory:
if not folderPath.get() == "":                          ## make sure not blank
    source = folderPath.get()                           ## set source path 
    size = 0
    broken = False

    for fname in os.listdir(source):
        if  fname.lower().endswith(extensions):
            imageName = source+"\\"+fname               ## set the source location of the image
            try: 
                img = Image.open(imageName)
                width, height = img.size                    ## get the dimensions
                size = width * height / 1000
                broken = False
                img.close()
            except IOError, e:
                broken = True
                img.close()

            if ( broken == True ):
                def handleRemoveReadonly(func, path, exc):
                    excvalue = exc[1]
                    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
                        os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO)
                        func(path)
                    else:
                        raise
                try:
                    os.remove(imageName)                ## Remove all remaining images that don't match the preset requirements (<400 and is an image)

额外信息

请注意我也在使用GUI,因此&#34; resultMessage&#34;和类似的输出/输入字段就是这个原因。

修改

在与@Cyphase进行来回讨论后,我确定了问题所在。这些失败的帖子是由于我为他编辑OP并带回溯。我不是真的使用这个论坛,因为我通常不需要编码。可能会出现此应用的更多主题。感谢。

2 个答案:

答案 0 :(得分:4)

您的问题是您正在修改基础文件系统(通过删除图像),然后循环遍历(旧)文件列表。

这就是你的循环试图打开不再存在的图像的原因。

解决方案是首先存储文件列表,然后循环遍历文件列表;而不是os.listdir()的输出(将被缓存)。

您还应该分解代码的一些组件。试试这个版本:

from itertools import izip_longest

# https://docs.python.org/2/library/itertools.html
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

def get_valid_images(image_path):
    extensions = ['*.jpg']
    return [f for f in os.listdir(image_path)
            if f.lower().endswith(extensions)]

def is_valid_image(image_path):
    try:
        img = Image.open(image_path)
        img.load()
        width, height = img.size
        img.close()
        return True
     except IOError as e:
        print(e)
        img.close()
        return None
     finally:
        img.close()
    return None

def confirmIt():
    # Confirm selection and move files to new sub-directory
    source = folderPath.get()  # set source path
    if not source:
        return False # If there is no source no point going
                     # head
    file_list = get_valid_images(source)
    valid_images = []
    for fname in file_list:
        image_dim = is_valid_image(os.path.join(source, fname))
        if image_dim:
            valid_images.append(source)

    # Now, group the resulting list in bunches for your move
    for dir_num, filenames in enumerate(grouper(valid_images, 5)):
        dest = os.path.join(source, str(dir_num))
        if not os.path.exists(dest):
            try:
                os.makedirs(dest)
            except OSError, e:
                print(e)
                continue # Skip this set, as we cannot make the dir
        for fname in filenames:
            shutil.move(fname, dest)
            print('Moving {}'.format(fname))

答案 1 :(得分:1)

经过多次来回,这段代码应该做你想要的,除非任何错误:)。对任何人;可能会有一些更改,以解决任何问题。

from __future__ import print_function

import errno
import os

try:
    from itertools import zip_longest  # Python 3
except ImportError:  # Python 2
    from itertools import izip_longest as zip_longest  # Python 2

from PIL import Image

DEFAULT_IMAGE_EXTS = ('.jpg',)


# From the recipes section of the itertools documentation:
# https://docs.python.org/3/library/itertools.html#itertools-recipes
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)


def makedirs(d):
    try:
        os.makedirs(d)
    except OSError as e:
        # If the file already exists, and is a directory
        if e.errno == errno.EEXIST and os.path.isdir(d):
            created = False
        # It's some other error, or the existing file is not a directory
        else:
            raise
    else:
        created = True

    return created


def get_valid_filenames(directory, extensions):
    for filename in os.listdir(directory):
        if filename.lower().endswith(extensions):
            yield filename


def get_corrupt_image_filenames(directory, extensions=DEFAULT_IMAGE_EXTS):
    for filename in get_valid_filenames(directory, extensions):
        image_path = os.path.join(directory, filename)
        try:
            with open(image_path, 'rb') as filehandle:
                Image.open(filehandle)
                # img = Image.open(filehandle)
                # img.load()  # I don't think this is needed, unless
                #               the corruption is not in the header.
        except IOError:
            yield filename


def confirm_it(directory, extensions, images_per_dir=5000):
    # Confirm selection and move files to new sub-directory
    if directory:
        for corrupt_file_name in get_corrupt_image_filenames(directory):
            os.remove(os.path.join(directory, corrupt_file_name))

        valid_images = get_valid_filenames(directory, extensions)
        grouped_image_file_names = grouper(valid_images, images_per_dir)
        for subdir, image_filenames in enumerate(grouped_image_file_names):
            for filename in image_filenames:
                from_path = os.path.join(directory, filename)
                to_dir = os.path.join(directory, str(subdir))
                to_path = os.path.join(to_dir, filename)

                makedirs(to_dir)

                os.rename(from_path, to_path)


def confirm_it_wrapper():
    confirm_it(directory=folderPath.get(), extensions=extensions)

使用confirm_it_wrapper代替confirm_it作为tkinter Button点击的回调。