Статья Сортируем файлы с помощью библиотеки pathlib в Python. Практический пример применения

У каждого из нас в какой-либо из папок скапливается большое количество файлов, рассортировать которые все никак не доходят руки. Мне приходилось наблюдать папку «Загрузки» забитую неимоверным количеством файлов, «Рабочие столы», фото на которых лежит почти друг на друге. И у меня иногда скапливаются файлы, на сортировку которых уходит время. А что, если написать небольшой скрипт на Python, который рассортирует файлы по расширениям и разложит по папкам, попутно удалив пустые директории автоматически? Давайте сделаем это.

000.jpg

Думаю, что не сделаю никаких открытий, сказав, что рассортировать файлы можно с использованием одной библиотеки pathlib, а точнее, ее модуля Path. Каюсь, до недавнего времени, почему-то не обращал на эту библиотеку должного внимания. Может быть потому, что она не представляет из себя ничего экзотического. Но, вот попалась она мне на глаза и попробовав с ней работать я понял, насколько это удобнее, когда идет работа с файлами, чем использовать модуль os. С помощью данного модуля можно получить как полный путь к файлу, так и его расширение, имя, просто путь к папке с файлом и многое другое. А также выполнять базовые операции по удалению, переименованию и перемещению файлов.

Данная заметка, это скорее пример использования данного модуля в практических целях. Ну и кто знает, может быть данный код будет кому-нибудь полезен.


Что потребуется?

Для того, чтобы написать данный скрипт не потребуется скачивать никаких сторонних библиотек, так как библиотека pathlib является предустановленной вместе с Python. Поэтому, нам нужно ее только импортировать в наш скрипт.

from pathlib import Path

Создаем словарь с названиями директорий и расширениями привязанными к ним. Ключом в данном словаре будет название директории, например: «Images», а значением список с расширениями: [".pdf"]. В полном виде данный словарь будет выглядеть вот так:

Python:
dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".md", ".epub", ".txt", ".docx", ".doc", ".ods", ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "Audio": [".aac", ".m4a", ".mp3", "ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}

Конечно же, вы можете самостоятельно добавить директории, а также типы файлов которые нужно будет в них отсортировать. И это, по сути, самая трудоемкая часть данного скрипта.
Теперь создадим функцию, которая на входе будет принимать путь к директории, в которой нужно сортировать файлы. Назову ее: sort_func(path_dir).
Для начала создам переменную, которая будет хранить путь к целевой директории, преобразованной с помощью модуля Path.

Python:
cur_dir = Path(path_dir)

Теперь запускаю цикл по целевой директории, из которой, с помощью функции iterdir() получаю список файлов. В данном случае переменная file будет содержать полный путь к файлу в директории.

Python:
for file in cur_dir.iterdir():

Затем проверяю, является ли объект полученный в цикле папкой, ведь в директории могут содержаться не только файлы. Проверяю размер папки, и если он равен 0, значит она пустая, а следовательно, ее можно удалить. Что и делается с помощью функции rmdir().

Python:
        if file.is_dir():
            if file.stat().st_size == 0:
                file.rmdir()

Запускаю еще один цикл, в котором уже перебираю содержимое созданного ранее словаря с директориями и расширениями. Проверяю, содержится ли расширение файла в директории в списке ключа.

Python:
        for suff in dir_suff_dict:
            if file.suffix.lower() in dir_suff_dict[suff]:

Если да, создаем директорию с названием ключа. Здесь не требуется проверки на наличие или отсутствие директории. Все дело в ключе exist_ok=True, который позволяет игнорировать исключение FileExistsError возникающее, если директория уже существует. И затем, перемещаю текущий файл в только что созданную директорию, где в качестве пути, куда перемещать файл указывается имя созданной директории объединенное с именем файла, который нужно переместить.

Python:
                dir_img = cur_dir / suff
                dir_img.mkdir(exist_ok=True)
                file.rename(dir_img.joinpath(file.name))

Полный код функции сортировки файлов:

Python:
def sort_func(path_dir):
    cur_dir = Path(path_dir)
    for file in cur_dir.iterdir():
        if file.is_dir():
            if file.stat().st_size == 0:
                file.rmdir()
        for suff in dir_suff_dict:
            if file.suffix.lower() in dir_suff_dict[suff]:
                dir_img = cur_dir / suff
                dir_img.mkdir(exist_ok=True)
                file.rename(dir_img.joinpath(file.name))

Ну и код для запуска функции. Для начала запрашиваем у пользователя путь к директории для сортировки. Проверяем, существует ли данная директория. Если нет, сообщаем об этом пользователю. Если да, запускаем функцию сортировки, в которую передаем путь к директории. А по окончании сортировки сообщаем об этом пользователю.

Python:
if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')

Вот в принципе и все. Хочу сказать, что по удобству работы с файлами данная библиотека намного превосходит библиотеку os. Конечно же, это не говорит о том, что она ее полностью заменяет. Но, могу сказать, что если раньше я, можно сказать, мучился, когда мне нужно было получить расширение файла или его имя без расширения, то теперь, сделать это легко и просто. Одно могу сказать точно, на данную библиотеку нужно было обратить внимание еще раньше.

Но, к моему сожалению, не скажу за всех, но в тех видео и книгах для новичков почему-то очень подробно рассматривается библиотека os, а вот упоминание о pathlib я почти не встречал. По крайней мере, не помню об этом. Встречал данную библиотеку в статьях, но почему-то считал ее сторонней.

Ну и демонстрация работы библиотеки. Вот как выглядела директория до сортировки:

dir01.png

А так уже после:

dir02.png

Python:
from pathlib import Path

dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".md", ".epub", ".txt", ".docx", ".doc", ".ods", ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "Audio": [".aac", ".m4a", ".mp3", "ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}


def sort_func(path_dir):
    cur_dir = Path(path_dir)
    for file in cur_dir.iterdir():
        if file.is_dir():
            if file.stat().st_size == 0:
                file.rmdir()
        for suff in dir_suff_dict:
            if file.suffix.lower() in dir_suff_dict[suff]:
                dir_img = cur_dir / suff
                dir_img.mkdir(exist_ok=True)
                file.rename(dir_img.joinpath(file.name))


if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')

А на этом, пожалуй, все.

Спасибо за внимание. Надеюсь, что данная информация будет вам полезна
 

Karhad

One Level
27.09.2022
1
1
BIT
0
Тема супер! Спасибо! Добавил немного форматов, вдруг кому пригодится

Python:
from pathlib import Path

dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".conf", ".md", ".epub", ".txt", ".docx", ".doc", ".ods",
                               ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "APKS": [".apk", ".npbk"],
                 "BATCH": [".bat", ".sh"],
                 "LUA": ['.lua'],
                 "PSD": ['.psd'],
                 "Audio": [".aac", ".m4a", ".mp3", ".ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}


def sort_func(path_dir):
    cur_dir = Path(path_dir)
    for file in cur_dir.iterdir():
        if file.is_dir():
            try:
                if file.stat().st_size == 0:
                    file.rmdir()
            except OSError:
                pass
        for suff in dir_suff_dict:
            if file.suffix.lower() in dir_suff_dict[suff]:
                dir_img = cur_dir / suff
                dir_img.mkdir(exist_ok=True)
                file.rename(dir_img.joinpath(file.name))


if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')
    input()
 
  • Нравится
Реакции: Johan Van

meteor630

Member
28.09.2022
5
0
BIT
0
а как сделать так чтобы программа заходила и вытаскивала из папок эти файлы а не сами папки копировала?
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
а как сделать так чтобы программа заходила и вытаскивала из папок эти файлы а не сами папки копировала?

Так папки и так не копируются. Файлы перемещаются в нужные папки. Вот же код:
file.rename(dir_img.joinpath(file.name))
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
Посмотреть вложение 63435
Посмотреть вложение 63436
странно ибо у меня не затрагивает папку изображений и в случае с кучей папок вылезает ошибка
Посмотреть вложение 63437

Ну так у вас ошибка при попытке удаления папки. Папка не может быть удалена, так как в ней скорее всего содержится файл миниатюр изображений. А значит, она не удалится. Здесь нужно дополнительно условие добавить, что если у файла расширение .thumb (вроде так...) то его нужно удалить. То есть, этот файл не перемещать, а удалить. А после уже удалять папку.
 

meteor630

Member
28.09.2022
5
0
BIT
0
Ну так у вас ошибка при попытке удаления папки. Папка не может быть удалена, так как в ней скорее всего содержится файл миниатюр изображений. А значит, она не удалится. Здесь нужно дополнительно условие добавить, что если у файла расширение .thumb (вроде так...) то его нужно удалить. То есть, этот файл не перемещать, а удалить. А после уже удалять папку.
если честно я не программист и не особо понимаю что именно надо сделать) а нормальных скриптов помимо этого не нашел в интернете
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
если честно я не программист и не особо понимаю что именно надо сделать) а нормальных скриптов помимо этого не нашел в интернете

Мне сложно сказать, почему у вас не удаляется папка. Возможно помимо этого файла в ней есть еще какие-то скрытые. Я попробую у себя смоделировать ситуацию. Не гарантирую, что получиться смоделировать. У меня еще вопрос есть, а у вас эта папка к приложению привязана?
 

meteor630

Member
28.09.2022
5
0
BIT
0
Мне сложно сказать, почему у вас не удаляется папка. Возможно помимо этого файла в ней есть еще какие-то скрытые. Я попробую у себя смоделировать ситуацию. Не гарантирую, что получиться смоделировать. У меня еще вопрос есть, а у вас эта папка к приложению привязана?
нет, у меня есть куча папок(около 3к) с png изображениями, они ни к какой программе не привязаны и скачены из интернета, сами папки из новеллы и возможно это имеет значение, у них в названии есть что-то типа расширения и в каждой папке по одному-три изображения

1664420150181.png
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
нет, у меня есть куча папок(около 3к) с png изображениями, они ни к какой программе не привязаны и скачены из интернета, сами папки из новеллы и возможно это имеет значение, у них в названии есть что-то типа расширения и в каждой папке по одному-три изображения

Посмотреть вложение 63438

Хорошо. Я сейчас посмотрю, что можно сделать и напишу вам.
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
нет, у меня есть куча папок(около 3к) с png изображениями, они ни к какой программе не привязаны и скачены из интернета, сами папки из новеллы и возможно это имеет значение, у них в названии есть что-то типа расширения и в каждой папке по одному-три изображения

Посмотреть вложение 63438

Немного переделал код. То, что у папок что-то вроде расширения, роли не играет. Просто Path не обходил все папки рекурсивно. А только указанную папку верхнего уровня. Поэтому пришлось добавить os.walk. Соответственно, вот что получилось:

Python:
import os
from pathlib import Path

dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".md", ".epub", ".txt", ".docx", ".doc", ".ods", ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "Audio": [".aac", ".m4a", ".mp3", "ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}


def sort_func(path_dir):
    cur_dir = Path(path_dir)
    dir_path = []

    for root, dirs, files in os.walk(path_dir):
        for d in dirs:
            dir_path.append(os.path.join(root, d))
        for file in files:
            p_file = Path(root) / file
            for suff in dir_suff_dict:
                if p_file.suffix.lower() in dir_suff_dict[suff]:
                    dir_img = cur_dir / suff
                    dir_img.mkdir(exist_ok=True)
                    try:
                        p_file.rename(dir_img.joinpath(p_file.name))
                    except FileExistsError:
                        p_file.rename(dir_img.joinpath(f'{p_file.name.split(".")[0]}_c{p_file.suffix}'))
                        print(f"Возможно дубликат: {p_file.name}")

    for dir_p in reversed(dir_path):
        if os.path.split(dir_p)[1] in dir_suff_dict or os.stat(dir_p).st_size != 0:
            continue
        else:
            os.rmdir(dir_p)


if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')

Попробуйте для начала на тестовых файлах, чтобы проверить, как работает. У меня проблем с удалением папок не наблюдалось.
 

meteor630

Member
28.09.2022
5
0
BIT
0
Немного переделал код. То, что у папок что-то вроде расширения, роли не играет. Просто Path не обходил все папки рекурсивно. А только указанную папку верхнего уровня. Поэтому пришлось добавить os.walk. Соответственно, вот что получилось:

Python:
import os
from pathlib import Path

dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".md", ".epub", ".txt", ".docx", ".doc", ".ods", ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "Audio": [".aac", ".m4a", ".mp3", "ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}


def sort_func(path_dir):
    cur_dir = Path(path_dir)
    dir_path = []

    for root, dirs, files in os.walk(path_dir):
        for d in dirs:
            dir_path.append(os.path.join(root, d))
        for file in files:
            p_file = Path(root) / file
            for suff in dir_suff_dict:
                if p_file.suffix.lower() in dir_suff_dict[suff]:
                    dir_img = cur_dir / suff
                    dir_img.mkdir(exist_ok=True)
                    try:
                        p_file.rename(dir_img.joinpath(p_file.name))
                    except FileExistsError:
                        p_file.rename(dir_img.joinpath(f'{p_file.name.split(".")[0]}_c{p_file.suffix}'))
                        print(f"Возможно дубликат: {p_file.name}")

    for dir_p in reversed(dir_path):
        if os.path.split(dir_p)[1] in dir_suff_dict or os.stat(dir_p).st_size != 0:
            continue
        else:
            os.rmdir(dir_p)


if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')

Попробуйте для начала на тестовых файлах, чтобы проверить, как работает. У меня проблем с удалением папок не наблюдалось.
сработало, спасибо огромное за уделенное время, в ручную пришлось бы несколько часов сортировать)
 

doS100

New member
25.10.2022
3
0
BIT
0
Не за что, рад, что это вам пригодилось )
Добрый день. Вы бы не могли помочь в интеграции в этот код функции нормализации (когда нужно например кириллицу в именах файлов преобразовать в английские буквы) К примеру:
Python:
def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
Добрый день. Вы бы не могли помочь в интеграции в этот код функции нормализации (когда нужно например кириллицу в именах файлов преобразовать в английские буквы) К примеру:
Python:
def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name

Добрый день. Я подумаю, как лучше сделать и отпишусь. Не сразу, так как немного занят, но о результате вам напишу.
Уточняющий вопрос: Если я вас правильно понял, то нужно просто рекурсивно прочитать директорию и переименовать все файлы?
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
Добрый день. Вы бы не могли помочь в интеграции в этот код функции нормализации (когда нужно например кириллицу в именах файлов преобразовать в английские буквы) К примеру:
Python:
def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name

Используя вашу функцию я сделал так:

Python:
import os
import re
from pathlib import Path


def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name


def dir_rename(path: str):
    for root, dirs, files in os.walk(path):
        for name in files:
            path_obj = Path(root) / name
            path_obj.rename(Path(root) / f"{normalize(path_obj.name[0:-len(path_obj.suffix)])}{path_obj.suffix}")


def main():
    path = input("Введите путь к директории для нормализации: ")
    dir_rename(path)
    print("Операция завершена")


if __name__ == "__main__":
    main()

То есть, для начала, с помощью os.walk рекурсивно считываем содержимое директории. Затем, перебираем полученные файлы и создаем из них объекты Path для того, чтобы можно было ими манипулировать. Затем, переименовываем файл уже в английской раскладке.

f"{normalize(path_obj.name[0:-len(path_obj.suffix)])}{path_obj.suffix}"

То есть, здесь мы для начала узнаем длину расширения файла, так как ее нам переименовывать не нужно, а метод name из Path возвращает имя файла с расширением. split делить не вариант, так как в имени файла могут попасться точки. После чего делаем срез в имени файла, normalize(path_obj.name[0:-len(path_obj.suffix)]), где отсекается расширение, прогоняем через функцию нормализации. И в конце добавляем в f-строке расширение. Для того, чтобы это у нас получился полноценный объект Path, добавляем его в начале.

Вот, в принципе и все. То есть, для примера, с вашей функцией нормализации:

01.png

02.png
 

doS100

New member
25.10.2022
3
0
BIT
0
Используя вашу функцию я сделал так:

Python:
import os
import re
from pathlib import Path


def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name


def dir_rename(path: str):
    for root, dirs, files in os.walk(path):
        for name in files:
            path_obj = Path(root) / name
            path_obj.rename(Path(root) / f"{normalize(path_obj.name[0:-len(path_obj.suffix)])}{path_obj.suffix}")


def main():
    path = input("Введите путь к директории для нормализации: ")
    dir_rename(path)
    print("Операция завершена")


if __name__ == "__main__":
    main()

То есть, для начала, с помощью os.walk рекурсивно считываем содержимое директории. Затем, перебираем полученные файлы и создаем из них объекты Path для того, чтобы можно было ими манипулировать. Затем, переименовываем файл уже в английской раскладке.

f"{normalize(path_obj.name[0:-len(path_obj.suffix)])}{path_obj.suffix}"

То есть, здесь мы для начала узнаем длину расширения файла, так как ее нам переименовывать не нужно, а метод name из Path возвращает имя файла с расширением. split делить не вариант, так как в имени файла могут попасться точки. После чего делаем срез в имени файла, normalize(path_obj.name[0:-len(path_obj.suffix)]), где отсекается расширение, прогоняем через функцию нормализации. И в конце добавляем в f-строке расширение. Для того, чтобы это у нас получился полноценный объект Path, добавляем его в начале.

Вот, в принципе и все. То есть, для примера, с вашей функцией нормализации:


Спасибо большое за Ваш труд и проделанную работу!! =) Я имел ввиду, в код, который вы писали для сортировки файлов по папкам и расширениям файлов, что бы можно было сделать сортировку файлов по папкам, и расширениям (video, audio, docs и т.д.) и в тоже время прошла функция нормализации для этих файлов. Прошу прощения, что краду ваше время.
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
Спасибо большое за Ваш труд и проделанную работу!! =) Я имел ввиду, в код, который вы писали для сортировки файлов по папкам и расширениям файлов, что бы можно было сделать сортировку файлов по папкам, и расширениям (video, audio, docs и т.д.) и в тоже время прошла функция нормализации для этих файлов. Прошу прощения, что краду ваше время.

Можно взять тогда код, который я писал в предыдущем ответе и добавить в него нормализацию. Не в самой статье. Там сортировка не рекурсивная. Сейчас гляну.
 

Johan Van

Green Team
13.06.2020
363
691
BIT
394
Спасибо большое за Ваш труд и проделанную работу!! =) Я имел ввиду, в код, который вы писали для сортировки файлов по папкам и расширениям файлов, что бы можно было сделать сортировку файлов по папкам, и расширениям (video, audio, docs и т.д.) и в тоже время прошла функция нормализации для этих файлов. Прошу прощения, что краду ваше время.

Вот код с добавленной функцией нормализации:

Python:
import os
import re
from pathlib import Path

dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".md", ".epub", ".txt", ".docx", ".doc", ".ods", ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "Audio": [".aac", ".m4a", ".mp3", "ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}


def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name


def sort_func(path_dir):
    cur_dir = Path(path_dir)
    dir_path = []

    for root, dirs, files in os.walk(path_dir):
        for d in dirs:
            dir_path.append(os.path.join(root, d))
        for file in files:
            p_file = Path(root) / file
            name_normalize = f"{normalize(p_file.name[0:-len(p_file.suffix)])}{p_file.suffix}"
            p_file.rename(Path(root) / name_normalize)
            p_file = Path(root) / name_normalize
            for suff in dir_suff_dict:
                if p_file.suffix.lower() in dir_suff_dict[suff]:
                    dir_img = cur_dir / suff
                    dir_img.mkdir(exist_ok=True)
                    try:
                        p_file.rename(dir_img.joinpath(p_file.name))
                    except FileExistsError:
                        p_file.rename(dir_img.joinpath(f'{p_file.name.split(".")[0]}_c{p_file.suffix}'))
                        print(f"Возможно дубликат: {p_file.name}")

    for dir_p in reversed(dir_path):
        if os.path.split(dir_p)[1] in dir_suff_dict or os.stat(dir_p).st_size != 0:
            continue
        else:
            os.rmdir(dir_p)


if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')

Для примера:

03.png

04.png

05.png

Вроде работает )) Сильно тестировать пока некогда ))

В данном коде добавилась ваша функция и вот эти вот строчки:

Python:
            name_normalize = f"{normalize(p_file.name[0:-len(p_file.suffix)])}{p_file.suffix}"
            p_file.rename(Path(root) / name_normalize)
            p_file = Path(root) / name_normalize
 
Последнее редактирование:

doS100

New member
25.10.2022
3
0
BIT
0
Вот код с добавленной функцией нормализации:

Python:
import os
import re
from pathlib import Path

dir_suff_dict = {"Images": ['.jpg', '.jpeg', '.png', '.gif', '.tiff', '.ico', '.bmp', '.webp', '.svg'],
                 "Documents": [".md", ".epub", ".txt", ".docx", ".doc", ".ods", ".odt", ".dotx", ".docm", ".dox",
                               ".rvg", ".rtf", ".rtfd", ".wpd", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".xml"],
                 "Archives": [".iso", ".tar", ".gz", ".7z", ".dmg", ".rar", ".zip"],
                 "Audio": [".aac", ".m4a", ".mp3", "ogg", ".raw", ".wav", ".wma"],
                 "Video": [".avi", ".flv", ".wmv", ".mov", ".mp4", ".webm", ".vob", ".mpg", ".mpeg", ".3gp"],
                 "PDF": [".pdf"],
                 "HTML": [".html", ".htm", ".xhtml"],
                 "EXE_MSI": [".exe", ".msi"],
                 "PYTHON": [".py", ".pyw"]}


def normalize(name: str) -> str:
    CYRILLIC_SYMBOLS = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
    TRANSLATION = (
    "a", "b", "v", "g", "d", "e", "e", "j", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u",
    "f", "h", "ts", "ch", "sh", "sch", "", "y", "", "e", "yu", "u", "ja")

    TRANS = {}
    for c, l in zip(CYRILLIC_SYMBOLS, TRANSLATION):
        TRANS[ord(c)] = l
        TRANS[ord(c.upper())] = l.upper()
    t_name = name.translate(TRANS)
    t_name = re.sub(r'\W', '_', t_name)
    return t_name


def sort_func(path_dir):
    cur_dir = Path(path_dir)
    dir_path = []

    for root, dirs, files in os.walk(path_dir):
        for d in dirs:
            dir_path.append(os.path.join(root, d))
        for file in files:
            p_file = Path(root) / file
            name_normalize = f"{normalize(p_file.name[0:-len(p_file.suffix)])}{p_file.suffix}"
            p_file.rename(Path(root) / name_normalize)
            p_file = Path(root) / name_normalize
            for suff in dir_suff_dict:
                if p_file.suffix.lower() in dir_suff_dict[suff]:
                    dir_img = cur_dir / suff
                    dir_img.mkdir(exist_ok=True)
                    try:
                        p_file.rename(dir_img.joinpath(p_file.name))
                    except FileExistsError:
                        p_file.rename(dir_img.joinpath(f'{p_file.name.split(".")[0]}_c{p_file.suffix}'))
                        print(f"Возможно дубликат: {p_file.name}")

    for dir_p in reversed(dir_path):
        if os.path.split(dir_p)[1] in dir_suff_dict or os.stat(dir_p).st_size != 0:
            continue
        else:
            os.rmdir(dir_p)


if __name__ == "__main__":
    path_d = input('[+] Введите путь к директории для сортировки: ')
    if not Path(path_d).exists():
        print('[-] Директории не существует')
    else:
        sort_func(path_d)
    print('[!] Сортировка завершена')

Для примера:




Вроде работает )) Сильно тестировать пока некогда ))

В данном коде добавилась ваша функция и вот эти вот строчки:

Python:
            name_normalize = f"{normalize(p_file.name[0:-len(p_file.suffix)])}{p_file.suffix}"
            p_file.rename(Path(root) / name_normalize)
            p_file = Path(root) / name_normalize
Огромное Спасибо !! Хорошего дня.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!