删除具有特定扩展名的文件,位于文本文件中的列表中

delete files with specific extension located as a list in a textfile

我目前正在尝试从网络服务器上清理一些媒体文件夹。问题是每个文件都以多种不同的分辨率复制,而且并非所有都相同。

例如:picture1.jpg 也有 picture1-150x150.jpgpicture1-100x100.jpgpicture1-50x50.jpg。 虽然其中很多是相同的,但也有很多是不同的。

所以我首先尝试了这个:

import os
    
 dir_name = "path"
 test = os.listdir(dir_name)
    
 for item in test:
    
     if item.endswith("150x150.jpg"):
         os.remove(os.path.join(dir_name, item))

它完成了它的工作,但在添加各种不同的分辨率和文件扩展名(jpg、jpeg、png、etcpp)后变得非常臃肿:

if item.endswith("-150x150.jpg"):
        os.remove(os.path.join(dir_name, item))
 if item.endswith("-100x100.jpg"):
        os.remove(os.path.join(dir_name, item))
 if item.endswith("-75x75.jpeg"):
        os.remove(os.path.join(dir_name, item))
 if item.endswith("-50x50.jpeg"):
        os.remove(os.path.join(dir_name, item))
 
       etc...

所以我尝试将这些决议输入文本文件并将其用作列表。

import os

dir_name = "path"
folder = os.listdir(dir_name)

with open('list.txt') as f:
    lines = f.read().splitlines()

for file in folder:
    if file.endswith(str(lines)):
        os.remove(os.path.join(dir_name, file))

虽然我能够在一定程度上阅读和修改代码,但这是我在 Google 半天后设法做到的。 因此,我恳请任何帮助或指导。

我认为您需要检查列表

的所有元素

然后,如果文件名中出现列表的元素,则将其删除

for file in folder:
    for line in lines:
        if file.endswith(str(line)):
        os.remove(os.path.join(dir_name, file))

endswith 方法接受一个元组作为参数,这意味着您可以将所有扩展合并到一个变量中。

extensions = ("-150x150.jpg","-100x100.jpg","-75x75.jpeg","-50x50.jpeg")

然后你把这个变量传给endswith

if file.endswith(extensions):
    os.remove(os.path.join(dir_name, file))

这是我用于概念验证的片段:

files = [
    "file1",
    "file2.jpg",
    "file123",
    "file4.jpg.old",
    "file5.txt"
]

extensions = (
    ".jpg",
    ".exe",
    ".txt"
)

for file in files:
    if file.endswith(extensions):
        print(f'File :{file} should be delete')
    else:
        print(f'Skipping:{file}')

返回:

╰─ python3 app.py
Skipping:file1
File :file2.jpg should be delete
Skipping:file123
Skipping:file4.jpg.old
File :file5.txt should be delete

除了“-150x150.jpg”之外,是否有任何文件名中包含破折号?如果没有,您可以执行以下操作:

import os

dir_name = "path"
folder = os.listdir(dir_name)

for file in folder:
    split_file_name = file.split('-')
    if len(split_file_name) > 1:
        os.remove(os.path.join(dir_name, file))

如果您不能保证只有一个破折号,那么我认为正则表达式将是您最好的选择。

import os
import re

dir_name = "path"
folder = os.listdir(dir_name)

pattern = re.compile('[a-zA-Z0-9_\-]+-\d+x\d+.jpg')

for file in folder:
    if pattern.match(file):
        os.remove(os.path.join(dir_name, file))

您可以简单地制作一个可以处理所有不同可能性的正则表达式,并使用它来过滤文件名。我使用您提供的循环编写了这个示例。您可以将其更改为循环到收集文件名所需的任何内容。这个例子的重点是正则表达式过滤器。

import re, os

dir_name = "path"
test     = os.listdir(dir_name)
    
fmt      = re.compile(r'([\w\d_]+)-\d{1,4}x\d{1,4}\.(jpg|png|jpeg|gif|bmp|tga)', re.I)
for item in test:
    if fmt.search(item):
         os.remove(os.path.join(dir_name, item))

如果您不理解正则表达式,这里有一个细分:

([\w\d_]+)

获取连续的单词、数字和下划线。 (例如:'my_family_pic1')。 + 表示至少应有 1 个单词、数字或下划线,但要尽可能多地连续出现。 + 的补充是 *,它将匹配描述数据的 0 次或多次连续出现。

-\d{1,4}x\d{1,4}

获取从“-0x0”到“-9999x9999”的任何组合。 {1,4} 部分只是说应该有 1 到 4 个连续的前面描述的类型的字符。在这种情况下,该类型将是数字。

\.(jpg|png|jpeg|gif|bmp|tga)

这部分的字面意思是我们期望一个点后跟 'jpg' OR 'png' OR 'jpeg' OR... 我们必须转义点,因为正则表达式中的点意味着“任何非空白字符”,除非我们使用 re.S 标志,在这种情况下,点将匹配任何内容。通过转义它,我们告诉正则表达式我们真的只是想找到一个点。 (group) 用于包含一组可能性,隔离逻辑 and/or 隔离一段数据,可以通过其组索引直接引用。如此处所用,您可以将其视为条件语句。如果我们在此处删除分组,则正则表达式将找到 ex:'some_file-10x10.jpg' 或完全失败。遇到ex:'.png'却只找ex:'png',永远匹配不到​​.


当前的正则表达式只会查找文件名中具有尺寸的图像(即.. -150x150)。如果你想删除任何图片,你可以将正则表达式更改为:

fmt = re.compile(r'([^.]+)\.(jpg|png|jpeg|gif|bmp|tga)', re.I)

这将从接受每个不是(^)点的字符开始,然后是点和扩展名。这相当于说“我们不关心开始,只要确保它以某种方式结束”。但是,如果实际文件名中有任何点,则此表达式将失败。我们不必在这里转义第一个点,因为它在 [character range] 内,这意味着我们将其称为字符。通常,[character range] 用于列出我们期望在此位置出现的所有字符或类型。当您以非 (^) 开始 [character range] 时,我们告诉正则表达式不应在此位置出现的所有字符和类型。

如果您决定使用正则表达式并需要更多信息,可以找到它 here。我上面的小入门书可能是所有关于它的知识的 15%。明白了这么多,剩下的学习起来就很简单了。

旁白:

如果我必须做你正在做的事情,我不会删除任何图像。我会将它们全部移动到一个带有日志的目录中,该日志记录了每个文件的来源。然后你可以确保它的 none 是你真正想要保留的东西。一旦您审核了所有图像并且确信整个目录都是垃圾,您就可以手动删除整个目录。换句话说,您的方式假定没有一张图片实际上是界面的一部分,并且根据查看它的设备进行引用。

首先,如果您正在 Linux 工作,解决这个问题的明显方法是使用 bash 文件:

# cleanup.sh
rm path/*-150x150.jpg
rm path/*-100x100.jpg
rm path/*-75x75.jpg
rm path/*-50x50.jpg

只需 运行 这个脚本,您就完成了。

如果您坚持使用Python,那么这个解决方案是对bash方法的翻译:

import os

dir_name = "path"
to_be_deleted = [
    "*-150x150.jpg",
    "*-100x100.jpg",
    "*-75x75.jpeg",
    "*-50x50.jpeg",
]

for wildcard in to_be_deleted:
    os.system(f"rm {dir_name}/{wildcard}")

更新

这个 bash 文件更短:

rm path/*-*x*.{jpg,jpeg}

更新 2

如果在 Windows 下,您可能没有 rm 命令,因此 Python 解决方案是使用 glob 库:

import glob
import os

dir_name = "path"
to_be_deleted = [
    "*-150x150.jpg",
    "*-100x100.jpg",
    "*-75x75.jpeg",
    "*-50x50.jpeg",
]

for wildcard in to_be_deleted:
    for path in  glob.glob(f"{dir_name}/{wildcard}"):
        os.remove(path)