Модуль hashlib, чтение EXIF и работа с файловой системой

Легенда для этого задания следующая. Из-за резкого скачка электричества ваш компьютер выключился во время записи файла на диск. В результате повреждена файловая система, поэтому уже невозможно найти свои файлы в "обычных" местах. На диске остались фотографии, которые вам дороги. С помощью специальной программы, которая сканирует весь диск и ищет последовательности байтов, похожие на фотографии, вы добыли всё, что можно. Так как файловая система умерла, то имён файлов и прочих атрибутов нет, есть только гора файлов с бессмысленными именами. Так как вы много работали с фотографиями, то там много повторов фотографий. А вот и архив с этими фотографиями. Для его распаковки под Windows можно использовать архиватор 7-Zip.

План по наведению порядка:

После распаковки архива фотографии будут находиться в каталоге resc_photos. Предполагается, что этот каталог находится в том же каталоге, что и ваша программа. Например, ваше решение может сделать команду os.chdir('resc_photos') для обработки.

При выполнении задания поощряется поиск готовых решений в интернете, прежде всего хорошим подспорьем является сайт stackoverflow.com.

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

print(2 ** 100)
"""
1267650600228229401496703205376
"""

A: sha1-хеши файлов

Для каждого файла из архива посчитайте его sha1-хеш. Выведите для каждого файла имя этого файла, а затем через пробел — его sha1-хеш. Файлы должны быть упорядочены по именам.

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

При вызове функций модуля hashlib вам понадобится считать двоичные данные, хранящиеся в файлах. Для этого необходимо открыть файл на чтение в двоичном режиме, что делается передачей параметра "rb" функции open. Например, open("image.jpg", "rb").

Если бы в архиве были бы только файлы 0spuuzog.jpg, 1e1ztfom.jpg и 82t56870.jpg, то правильный ответ был бы таким:

import os
import hashlib
...
"""
0spuuzog.jpg dd3f8e73dc19b80901c42ec551d6562e09c89a40
1e1ztfom.jpg 96363016d4463a09bb40c523e15fa3228c39a7d8
82t56870.jpg dd3f8e73dc19b80901c42ec551d6562e09c89a40
"""

B: Отбор уникальных файлов

Отберите все уникальные фотографии и выведите их имена.

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

Список имён файлов также должен быть выведен в лексикографическом порядке.

Если бы в архиве были бы только файлы 0spuuzog.jpg, 1e1ztfom.jpg и 82t56870.jpg, то правильный ответ был бы таким:

import os
...
"""
0spuuzog.jpg
1e1ztfom.jpg
"""

С: Удаление лишнего

Получите список всех файлов, которые не попали в список из предыдущей задачи, а также удаляет эти файлы с диска. Для удаления файлов воспользуйтесь функциями модуля os.

В тестирующую систему необходимо сдать код программы, которая удаляет ненужные файлы, а также выводит список удаляемых файлов в лексикографичесчком порядке. Если бы в папке были бы только файлы 0spuuzog.jpg, 1e1ztfom.jpg и 82t56870.jpg, то правильный ответ был бы таким:

import os
...
"""
82t56870.jpg
"""

D: Чтение EXIF

Теперь мы хотим упорядочить найденные фотографии, для чего хорошо подойдёт время съёмки. Цифровые камеры сохраняют дополнительные метаданные, например, дата-время съёмки, геолокация, модель камеры, ориентация камеры и т.д. внутри JPEG-файла, это так называемые данные EXIF.

Для чтения данных EXIF будем использовать модуль Pillow для библиотеки Python. Сначала вам понадобится установить его, для этого нужно использовать консольную команду pip. Запустите консоль и введите команду

pip install --user Pillow

В системе Linux вместо pip скорее всего нужно запускать pip3.

Если в системе Windows команда pip не найдена, то вам нужно добавить каталог, где находится программа pip.exe, это подкаталог Scripts каталога установки Python, то есть обычно он имеет путь вида C:\Program Files\Python310\Scripts.

Изучите документацию на Pillow или найдите в интернете, как считывать данные EXIF при помощи Pillow. Вам нужны данные момента съёмки.

Для каждого уникального файла из задачи B выведите имя файла и время его съёмки в том виде, в котором оно записано в EXIF. Выводите имена файлов в лексикографическом порядке.

Если бы в архиве были бы только файлы 0spuuzog.jpg, 1e1ztfom.jpg и 82t56870.jpg, то правильный ответ был бы таким:

import os
...
"""
0spuuzog.jpg 2015:08:23 14:26:12
1e1ztfom.jpg 2015:08:19 16:05:07
"""

E: Переименование

Теперь ничего не стоит переименовать файлы в имена вида "yyyy-mm-dd_hh-mm-ss.jpg". Мы выберем именно такую строку записи имён файлов, потому что использование двоеточие в имени файла в системе Windows затруднительно (оно используется для отделения имени диска от пути к файлу).

Однако возникнет проблема: могут быть файлы, снятые в одну секунду. Чтобы они не получили одинаковые имена, будем добавлять в конец имени файла перед ".jpg" один, два или три символа "_". То есть первый снятый файл в эту секунду получает имя "2015-08-23_14-26-12.jpg", второй файл, снятый в эту же секунду — "2015-08-23_14-26-12_.jpg", следующий файл — "2015-08-23_14-26-12__.jpg" и т.д.

Ваша программа должна удалять дубликаты, как это делалось в одном из предыдущих заданий, а уникальные файлы переименовывать в соответствии с временем съёмки.

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

Для однозначности проверки, все файлы обрабатываются в лексикографическом порядке имён.

import os
...
"""
0spuuzog.jpg 2015-08-23_14-26-12.jpg
1e1ztfom.jpg 2015-08-19_16-05-07.jpg
"""

F: Выбор объектива

При выборе объектива для фотоаппарата возникает вопрос: какие диапазон фокусных расстояний (углов поля зрения, см. картинку в википедии) вам необходим. Что выбирать, длиннофокусный объектив, широкоугольный объектив и т.д.? Довольно надёжный способ — посмотреть, какими фокусными расстояними вы пользуетесь.

Напишите программу, которая получает фокусное расстояние кадра из EXIF для каждой фотографии. Для каждого используемого фокусного расстояния выведите количество кадров, учитываются только уникальные фотографии. Выведите фокусное расстояние, через двоеточие: количество кадров, упорядочив по возрастанию фокусного расстояния.

Учтите, что вам нужно эквивалентное фокусное расстояние, так как именно оно участвует в маркировке объективов.

В тестирующую систему необходимо сдать код программы, которая делает это, а также выводит количества кадров. Если бы в папке были бы только файлы 0spuuzog.jpg, 1e1ztfom.jpg и 82t56870.jpg, то правильный ответ был бы таким:

import os
...
"""
24: 1
70: 1
"""

G: Разложить по полочкам

После того, как мы «восстановили» имена файлов с фотографиями, появилась необходимость разложить их в отдельные каталоги в соответствии с датами поездок.

Будем тренироваться на «кошках». Внутри архива вы найдёте несколько файлов вида 2013-02-04_04-46-01.txt. Нужно разложить их по каталогам вида yyyy/mm/dd, где yyyy, mm и dd — соответствующие части даты, а также переименовать: убрать из имени файла дату. Ваша программа будет запускаться из каталога, в котором будет находиться подкаталог crt_dirs из данного архива.

В тестирующую систему необходимо сдать zip-архив, в котором находится каталог crt_dirs с нужной структурой, а также py-файл с программой.

При этом для создания архива не следует использовать встроенный архиватор Windows, он создаёт некорректные архивы (они не могут быть проверены тестирующей системой). Используйте архиватор 7-zip для создания архива в Windows.

Если бы архив из условия состоял лишь из файлов 2013-01-16_00-24-33.txt, 2013-01-16_16-40-26.txt и 2015-11-25_16-51-47.txt, то в правильная структура в zip файле ответа выглядела бы так:

crt_dirs/2013/01/16/00-24-33.txt
crt_dirs/2013/01/16/16-40-26.txt
crt_dirs/2015/11/25/16-40-26.txt
my_pgm.py