2015-08-10 2 views
-2

RequirementPython удаление файлов - «В настоящее время используется другим процессом»

Я должен попытаться создать программу, которая удаляет все поврежденные изображения (и изображения, размер которых меньше, чем 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) 

Extra Info

Пожалуйста, обратите внимание, что я использую графический интерфейс, а поэтому "resultMessage" и аналогичных выходных/входных полей по этой причине.


EDIT:

После назад и вперед обсуждения с @Cyphase я определил, где вопросы были. Предыдущие сообщения были связаны с моим редактированием OP с отслеживанием для него. Я действительно не использую этот форум, поскольку мне обычно не нужно кодировать. Другие темы этого приложения могут возникнуть. Благодарю.


+0

Вы уверены, что некоторые другие процессы не открывают файл? Кроме того, почему вы определяете 'handleRemoveReadonly()' в блоке if, когда вы даже не используете его? – Cyphase

+1

Какой оператор является сообщением об ошибке, 'open',' rmdir' или 'remove'? – cdarke

+1

Обратите внимание, что удаление должно работать под POSIX, даже если другой процесс использует этот файл. Возможно, вам стоит подумать о том, чтобы пометить его любой операционной системой, которую вы используете (я бы предпочел окна). – skyking

ответ

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 мыши.

+0

@CFNZ_Techie, поврежденные файлы уже должны быть удалены, если вы не удалите этот код. – Cyphase

+1

Я скоро создам новую проблему и отвечу вам. Благодарю. –

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)) 
+0

Привет, Бухан ... Спасибо за это, я не принимал во внимание, что os.listdir хранит их в режиме кеша. Я подожду и посмотрю, что появилось в Cyphase, когда мы вышли в окончательную рабочую ситуацию, если у вас есть какие-то возможности добавить к нему то, что было бы здорово. –

Смежные вопросы