Python 删除文件 - "Currently being used by another process"
Python deletion of files - "Currently being used by another process"
要求
我必须尝试创建一个程序来删除所有损坏的图像(以及小于 400x400 的图像)并将其余图像过滤为 10,000 个一组。
问题
目前,当我尝试删除任何 "corrupt" 的图像时,它说该文件当前正被另一个进程使用,错误如下:
The process cannot access the file because it is being used by another process.
已走步数
我尝试了多种方法来释放文件,包括使用 "back pedal" 策略,应用程序移动到下一张图像,然后返回踏板以尝试删除该图像,但它仍然保持打开状态。
如果我尝试在 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,因此 "resultMessage" 和类似的 output/input 字段就是出于这个原因。
编辑:
在与@Cyphase 反复讨论后,我确定了问题所在。这些帖子是由于我为他编辑了带有回溯的 OP。我并没有真正使用这个论坛,因为我通常不需要编写代码。此应用程序的其他主题可能会出现。谢谢
经过反复反复,这段代码应该可以做你想做的,没有任何错误:)。给其他任何人;可能会进行更多更改以解决任何问题。
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
点击的回调。
您的问题是您正在修改底层文件系统(通过删除图像),然后遍历(旧)文件列表。
这就是您的循环尝试打开不再存在的图像的原因。
解决方法是先存储文件列表,然后循环遍历文件列表;而不是 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))
要求
我必须尝试创建一个程序来删除所有损坏的图像(以及小于 400x400 的图像)并将其余图像过滤为 10,000 个一组。
问题
目前,当我尝试删除任何 "corrupt" 的图像时,它说该文件当前正被另一个进程使用,错误如下:
The process cannot access the file because it is being used by another process.
已走步数
我尝试了多种方法来释放文件,包括使用 "back pedal" 策略,应用程序移动到下一张图像,然后返回踏板以尝试删除该图像,但它仍然保持打开状态。 如果我尝试在 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,因此 "resultMessage" 和类似的 output/input 字段就是出于这个原因。
编辑:
在与@Cyphase 反复讨论后,我确定了问题所在。这些帖子是由于我为他编辑了带有回溯的 OP。我并没有真正使用这个论坛,因为我通常不需要编写代码。此应用程序的其他主题可能会出现。谢谢
经过反复反复,这段代码应该可以做你想做的,没有任何错误:)。给其他任何人;可能会进行更多更改以解决任何问题。
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
点击的回调。
您的问题是您正在修改底层文件系统(通过删除图像),然后遍历(旧)文件列表。
这就是您的循环尝试打开不再存在的图像的原因。
解决方法是先存储文件列表,然后循环遍历文件列表;而不是 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))