Johan Van
Green Team
- 13.06.2020
- 367
- 700
Огромное Спасибо !! Хорошего дня.
Не за что. Вам то же
Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе
Огромное Спасибо !! Хорошего дня.
У каждого из нас в какой-либо из папок скапливается большое количество файлов, рассортировать которые все никак не доходят руки. Мне приходилось наблюдать папку «Загрузки» забитую неимоверным количеством файлов, «Рабочие столы», фото на которых лежит почти друг на друге. И у меня иногда скапливаются файлы, на сортировку которых уходит время. А что, если написать небольшой скрипт на Python, который рассортирует файлы по расширениям и разложит по папкам, попутно удалив пустые директории автоматически? Давайте сделаем это.
Думаю, что не сделаю никаких открытий, сказав, что рассортировать файлы можно с использованием одной библиотеки 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 я почти не встречал. По крайней мере, не помню об этом. Встречал данную библиотеку в статьях, но почему-то считал ее сторонней.
Ну и демонстрация работы библиотеки. Вот как выглядела директория до сортировки:
А так уже после:
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('[!] Сортировка завершена')
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, что данная информация будет вам полезна
import os
import re
from pathlib import Path
dir_suf_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 move_file(dir_p: Path, path_file: Path):
"""
Создается папка с названием группы расширений.
Перемещается текущий файл в созданную папку.
:param dir_p: объект Path для создания папки.
:param path_file: объект Path содержащий путь к файлу.
"""
dir_p.mkdir(exist_ok=True)
if (Path(dir_p) / path_file.name).exists():
path_file.rename(dir_p.joinpath(f'{path_file.name[0:-len(path_file.suffix)]}_c{path_file.suffix}'))
print(f"Возможно дубликат: {path_file.name}")
else:
path_file.rename(dir_p / path_file.name)
def extension_comparison(curr_dir: Path, path_file: Path, suf: str) -> bool:
"""
Выполняется проверка, входит ли расширение текущего файла
хотя бы в одну из групп представленных в словаре. Если входит -
возвращается True, нет - False.
:param curr_dir: объект Path с путем к директории проверки.
:param path_file: объект Path с путем к текущему файлу.
:param suf: строка, содержащая ключ из словаря с группами расширений.
:return: True или False, в зависимости от результатов проверки.
"""
if path_file.suffix in dir_suf_dict[suf]:
move_file(Path(curr_dir) / suf, path_file)
return True
return False
def name_normalize(root: str, file: str) -> Path:
"""
Нормализации (приведение к нужному виду, то есть, в данном случае
замена кириллицы на латинские буквы).
Переименование текущего файла в соответствии с результатами нормализации.
:param root: строка с путем к текущему файлу.
:param file: имя текущего файла с расширением.
:return: объект Path с путем к переименованному файлу.
"""
path_file = Path(root) / file
normalize_n = f"{normalize(path_file.name[0:-len(path_file.suffix)])}{path_file.suffix}"
path_file = path_file.rename(Path(root) / normalize_n)
return path_file
def remove_dir(subdir: list):
"""
Удаление пустых директорий, которые остались
после перемещения из них файлов при сортировке.
:param subdir: список с абсолютными путями к удаляемым директориям.
"""
for path in subdir:
if len(os.listdir(path)) > 0 or Path(path).name in dir_suf_dict:
continue
Path(path).rmdir()
def sort_func(path_d: str) -> tuple:
"""
Сортировка файлов на основе расширения, а также вхождении
расширения в одну из групп из словаря.
Создаются списки с начальными поддиректориями в директории сортировки.
Нормализация (замена кириллицы на латиницу) имен файлов.
Проверка принадлежности расширения файла к одной из групп словаря.
Перемещение в соответствии с принадлежностью к группе или, если принадлежности
к группе не найдено, в папку "Other".
Удаление пустых папок после сортировки.
:param path_d: строка содержащая путь к директории для сортировки.
:return: кортеж из списков с распознанными и не распознанными расширениями.
"""
curr_dir = Path(path_d)
subdir = []
known_extensions, unknown_extensions = set(), set()
for root, dirs, files in os.walk(path_d):
for d in dirs:
if not d:
continue
subdir.append(f"{curr_dir / d}")
for file in files:
path_file = name_normalize(root, file)
ex_comp = False
for suf in dir_suf_dict:
ex_comp = extension_comparison(curr_dir, path_file, suf)
if ex_comp:
known_extensions.add(path_file.suffix)
break
if not ex_comp:
move_file(Path(curr_dir) / "Other", path_file)
unknown_extensions.add(path_file.suffix)
remove_dir(subdir)
return list(known_extensions), list(unknown_extensions)
def main():
"""
Запрос у пользователя директории для сортировки файлов.
Проверка директории на существование.
Запуск функции сортировки с передачей полученного от пользователя пути.
Проверка количества элементов в возвращенных словарях. Если кол-во элементов
меньше или равно 0, сообщение не печатается. Если больше нуля, то
выводиться в терминал список полученный после работы функции сортировки.
"""
known, unknown = "", ""
path_d = input('[+] Введите путь к директории для сортировки: ')
if not Path(path_d).exists():
print('[-] Директории не существует')
else:
known, unknown = sort_func(path_d)
if len(known) >= 0:
print(f"\nРаспознанные расширения:\n{known}")
if len(unknown) >= 0:
print(f"Не распознанные расширения:\n{unknown}")
print('[!] Сортировка завершена')
if __name__ == "__main__":
main()
Добрый день! пытаюсь добавить в Ваш код еще несколько условийВот код с добавленной функцией нормализации:
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
Добрый день! пытаюсь добавить в Ваш код еще несколько условий
- скрипт игнорирует папки archives, video, audio, documents, images;
- распакованное содержимое архива переносится в папку archives в подпапку, названную точно так же, как и архив, но без расширения в конце;
- файлы, расширения которых неизвестны, остаются без изменений.
но пока столкнулся с проблемой работы с архивами.
Если у вас будет возможность подсказать как это реализовать, буду очень благодарен
Обучение наступательной кибербезопасности в игровой форме. Начать игру!