SHA-256 и хеш содержимого файла
Одинаковое содержимое всегда даёт одинаковый дайджест SHA-256. Поблочное чтение не требует держать в памяти весь файл разом.
Хеш-функция превращает содержимое файла произвольного размера в
строку фиксированной длины — дайджест. SafeSort использует
SHA-256 из модуля hashlib: одинаковые байты
всегда дают одинаковый дайджест, а разные дайджесты гарантированно значат разное
содержимое. Хеширование many-to-one: возможных входов больше, чем
256-битных результатов, поэтому разные входы математически могут иметь один дайджест.
Совпадающий дайджест служит сильным фильтром, но не доказывает равенство файлов.
Поскольку SafeSort перемещает настоящие файлы пользователя, он не останавливается на
совпадении дайджеста — следующая страница показывает последний шаг, который превращает
совпадение хеша в подтверждённый дубликат.
def sha256_stream(stream: BinaryIO, chunk_size: int = 1024 * 1024) -> str:
digest = hashlib.sha256()
while chunk := stream.read(chunk_size):
digest.update(chunk)
return digest.hexdigest()
При лавинном эффекте малое изменение входа обычно меняет много битов выхода; для идеализированного поведения ожидают примерно половину выходных битов. Это не означает, что в каждом опыте обязана измениться каждая шестнадцатеричная цифра.
Зачем читать файл частями
Цикл while chunk := file.read(chunk_size) читает файл не
целиком, а блоками по мегабайту, и каждый блок сразу добавляет к дайджесту через
digest.update(). Если бы функция читала файл одним вызовом
file.read(), для файла в несколько гигабайт программе
пришлось бы держать в оперативной памяти всё его содержимое разом. При поэтапном чтении
в памяти в любой момент находится только один блок, независимо от размера файла целиком.
>>> from pathlib import Path
>>> from safesort.duplicates import sha256_file
>>> sha256_file(Path("otchet.pdf"))
'784cc58b2286b83f67f58ffb1968ca4b80d1d0615863ad9b1ce9c3d05666f4e'