Многим из нас знакома ситуация, когда компьютер оказывался завален тоннами беспорядочных файлов. Только что вы открывали большой zip-архив, спустя мгновение – файлы повсюду в этой директории, вперемешку с важными документами. Наверняка приходилось мучительно скучно сортировать эту свалку вручную? Чтобы облегчить подобные задачи, мы сейчас погрузимся в «умную» работу с файлами при помощи Python.
«Работай умнее, а не усерднее». Карл Баркс
Итак, приступим, вооружившись Python версии 3.4 или выше. Сначала пройдемся по модулю OS, а по ходу дела познакомимся еще с несколькими. Всё, что мы будем использовать, доступно в Python «с коробки», так что ничего дополнительно устанавливать не потребуется.
Генератор случайных файлов
Создадим папку ManageFiles
, а внутри нее еще одну — RandomFiles
. Дерево каталогов теперь должно выглядеть вот так:
ManageFiles/ | |_RandomFiles/
Чтобы поиграться с файлами, мы сгенерируем их случайным образом в директории RandomFiles
. Создайте файл create_random_files.py
в папке ManageFiles
. Вот что должно получиться:
ManageFiles/ | |_ create_random_files.py |_RandomFiles/
Готово? Теперь поместите в файл следующий код, и перейдем к его рассмотрению:
import os from pathlib import Path import random list_of_extensions = ['.rst', '.txt', '.md', '.docx', '.odt', '.html', '.ppt', '.doc'] # перейти в папку RandomFiles os.chdir('./RandomFiles') for item in list_of_extensions: # создать 20 случайных файлов для каждого расширения имени for num in range(20): # пусть имя файла начинается со случайного числа от 1 до 50 file_name = random.randint(1, 50) file_to_create = str(file_name) + item Path(file_to_create).touch()
Начиная с Python 3.4 мы получили pathlib, нашу маленькую волшебную палочку. Также мы импортируем функцию random
для генерации случайных чисел, но ее мы посмотрим в действии чуть ниже.
Сперва создадим список файловых расширений для формирования названий файлов. Не стесняйтесь добавить туда свои варианты.
Далее мы переходим в папку RandomFiles
и запускаем цикл. В нем мы просто говорим: возьми каждый элемент list_of_extensions
и сделай с ним кое-что во внутреннем цикле 20 раз.
Теперь пришло время для импортированной функции random
. Используем ее для производства случайных чисел от 1 до 50. Это просто не очень творческий способ побыстрее дать названия нашим тестовым файлам: к сгенерированному числу добавим расширение файла и получим что-то вроде 23.txt
или 14.txt
. И так 20 раз для каждого расширения. В итоге образуется беспорядок, достаточный для того, чтобы его было лень сортировать вручную.
Итак, запустим наш генератор хаоса через терминал.
python create_random_files.py
Поздравляю, теперь у нас полная папка неразберихи. Будем распутывать.
В той же директории, где create_random_files.py
, создадим файл clean_up.py
и поместим туда следующий код.
Способ 1
import os import shutil import glob # перейти в папку RandomFiles os.chdir('./RandomFiles') # получить список файлов в папке RandomFiles files_to_group = [] for random_file in os.listdir('.'): files_to_group.append(random_file) # получить все расширения имен всех файлов file_extensions = [] for our_file in files_to_group: file_extensions.append(os.path.splitext(our_file)[1]) print(set(file_extensions)) file_types = set(file_extensions) for type in file_types: new_directory = type.replace(".", " ") os.mkdir(new_directory) # создать папку с именем данного расширения for fname in glob.glob(f'*.{type[1:]}'): shutil.move(fname, new_directory)
Для этого импортируем еще две библиотеки: shutil и glob. Первая поможет перемещать файлы, а вторая – находить и систематизировать. Но обо всем по порядку.
Для начала получим список всех файлов в директории.
Здесь мы предполагаем, что у нас нет ни малейшего понятия о том, какие именно файлы лежат в этой папке. Вместо того, чтобы вписывать все расширения вручную и использовать лестницу инструкций if или switch, мы желаем, чтобы программа сама просмотрела каталог и определила, на какие типы можно разделить его содержание. Что, если бы там были файлы с десятками расширений или логи? Вы бы стали описывать их вручную?
Получив список всех файлов, мы заходим в еще один цикл, чтобы извлечь расширения названий.
Обратите внимание на разделение строки:
os.path.splitext(our_file)[1]
Сейчас наша переменная our_file
выглядит как-нибудь так: 5.docx
. Когда разделим ее, получим следующее:
`('5', '.docx')`
Мы возьмем отсюда второй элемент по индексу [1], то есть .docx
. Ведь по индексу [0] у нас располагается 5.
Таким образом, у нас имеется список всех файловых расширений в папке, в том числе повторяющихся. Чтобы оставить только уникальные элементы, преобразуем его во множество. К примеру, если бы этот список состоял исключительно из .docx
, повторяющегося снова и снова, то в set остался бы всего один элемент.
# создать множество и присвоить его переменной file_types = set(file_extensions)
Заметим, что в списке типов файлов каждое расширение содержит .
в начале. Если мы назовем так папки на UNIX-системе, то они будут скрытыми, что не входит в наши намерения.
Поэтому, итерируя по нашему множеству, мы заменяем точку на пустую строку. И создаем папку с полученным названием.
new_directory = type.replace(".", " ") # наша директория теперь будет называться "docx"
Но чтобы переместить файлы, нам все еще нужно расширение .docx
.
for fname in glob.glob(f'*.{type[1:]}')
Этим попросту отбираем все файлы, оканчивающиеся расширением .docx
. Заметьте, что в f'*.{type[1:]}')
нет пробелов.
Символ подстановки *
обозначает, что подходит любое имя, если оно заканчивается на .docx
. Поскольку мы уже включили точку в поиск, мы используем [1:], что значит «все после первого символа». В нашем примере это docx
.
Что дальше? Перемещаем любые файлы с данным расширением в директорию с тем же названием.
shutil.move(fname, new_directory)
Таким образом, как только в цикле создана папка для первого попавшегося файла с данным расширением, все последующие файлы будут отправлены в нее же. Все будет сгруппировано без повторения каталогов.
Способ 2
В качестве хитрого способа создать список в одну строку можно использовать генераторы.
import os import shutil import glob # перейти в папаку RandomFiles os.chdir('./RandomFiles') # добавить все файлы в данной папке в список all_files = [x for x in os.listdir('.')] # создать множество расширений имен файлов в этой папке file_types = set((os.path.splitext(f)[1] for f in all_files)) for ftype in file_types: new_directory = ftype.replace(".", '') os.mkdir(new_directory) for fname in glob.glob(f'*.{ftype[1:]}'): shutil.move(fname, new_directory)
Оба варианта сработают, и все ваши файлы будут отсортированы по расширению.
ManageFiles/ | |_create_random_files.py |_RandomFiles/ |_doc |_docx |_html |_md |_odt |_ppt
Вот и все. Если вам когда-либо понадобится отсортировать файлы таким образом, вы сэкономите немало времени ?. Код упражнения доступен здесь.