Многим из нас знакома ситуация, когда компьютер оказывался завален тоннами беспорядочных файлов. Только что вы открывали большой 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
Вот и все. Если вам когда-либо понадобится отсортировать файлы таким образом, вы сэкономите немало времени ?. Код упражнения доступен здесь.

