Алгоритм определения идентификатора файла
Для проекта с открытым исходным кодом я пишу слой абстракции поверх файловой системы.
Этот уровень позволяет мне прикреплять метаданные и отношения к каждому файлу.
Я хотел бы, чтобы слой обрабатывал файлы, переименовывая изящно и поддерживая метаданные, если файл переименован/перемещен или скопирован.
Для этого мне понадобится механизм для вычисления идентичности файла. Очевидным решением является вычисление хэша SHA1 для каждого файла, а затем назначение метаданных для этого хеша. Но... это действительно дорого, особенно для фильмов.
Итак, я думал об алгоритме, который, хотя и не на 100% правильный, будет прав подавляющее большинство времени и будет дешевым.
Одним из таких алгоритмов может быть использование размера файла и выборки байтов для этого файла для вычисления хэша.
Какие байты я должен выбрать для образца? Как я могу считать расчет дешевым и достаточно точным? Я понимаю, что здесь есть компромисс, но производительность имеет решающее значение. И пользователь сможет обрабатывать ситуации, когда система делает ошибки.
Мне нужен этот алгоритм для работы с очень большими файлами (1GB + и крошечные файлы 5K)
EDIT
Мне нужен этот алгоритм для работы с NTFS и всеми SMB-ресурсами (linux или windows based), я бы хотел, чтобы он поддерживал ситуации, когда файл копируется из одного места в другое (существуют 2 физических копии, как один идентификатор), Я даже могу подумать о том, чтобы это работало в ситуациях, когда MP3 файлы перемаркированы (физический файл изменен, поэтому у меня может быть поставщик удостоверений на тип файла).
РЕДАКТИРОВАТЬ 2
Связанный вопрос: Алгоритм определения идентичности файлов (Оптимизация)
Ответы
Ответ 1
Как хранить некоторые случайные целые числа r i и искать байты (r i mod n), где n - размер файла? Для файлов с заголовками вы можете сначала их игнорировать, а затем выполнять этот процесс на оставшихся байтах.
Если ваши файлы на самом деле очень разные (не только разница в одном байте где-то, но, по крайней мере, на 1%), тогда случайный выбор байтов заметил бы это. Например, с 1% -ной разницей в байтах 100 случайных байтов не могли бы заметить с вероятностью 1/е ~ 37%; увеличение количества байтов, на которые вы смотрите, делает эту вероятность экспоненциально снижающейся.
Идея использования случайных байтов состоит в том, что они по существу гарантированы (ну, вероятностно говоря), чтобы быть такими же хорошими, как любая другая последовательность байтов, за исключением того, что они не подвержены некоторым проблемам с другими последовательностями (например, происходит с посмотрите на каждый 256-й байт формата файла, где этот байт должен быть 0 или что-то еще.)
Еще несколько советов:
- Вместо того, чтобы хватать байты, возьмите более крупные куски, чтобы оправдать затраты на поиск.
- Я бы предложил всегда смотреть на первый блок или около того файла. Из этого вы можете определить тип файла и т.д. (Например, вы можете использовать программу
file
.)
- По крайней мере, взвесить стоимость/преимущество чего-то вроде CRC всего файла. Это не так дорого, как реальная криптографическая хеш-функция, но по-прежнему требует чтения всего файла. Положительный результат будет означать однобайтовые различия.
Ответ 2
Bucketing, несколько уровней сравнения должны быть самыми быстрыми и масштабируемыми по всему диапазону файлов, которые вы обсуждаете.
Первый уровень индексации - это просто длина файла.
Второй уровень - хэш. Ниже определенного размера это хэш в целом файле. Кроме того, да, я согласен с вашей идеей алгоритма выборки. Проблемы, которые, как я думаю, могут повлиять на скорость выборки:
- Чтобы избежать попадания регулярно разнесенных заголовков, которые могут быть очень похожими или идентичными, вам нужно выполнить несоответствующее число, например: кратные простых или последовательных простых чисел.
- Избегайте шагов, которые могут столкнуться с обычными заголовками записей, поэтому, если вы получаете одинаковое значение из своих выборочных байтов, несмотря на другое местоположение, попробуйте отрегулировать шаг другим простым.
- Соблюдайте аномальные файлы с большими значениями одинаковых значений, потому что они являются незарегистрированными изображениями или просто заполнены нулями.
Ответ 3
Сделайте первые 128k, еще 128k на отметке 1mb, еще 128k на метке 10mb, еще 128k на отметке 100mb, еще 128k на отметке 1000mb и т.д. По мере увеличения размеров файлов, и это становится более вероятным что вы сможете отличить два файла в зависимости от их размера в отдельности, вы получаете меньшую и меньшую часть данных. Все под 128k полностью заботятся.
Ответ 4
Верьте или нет, я использую тики для последнего времени записи для файла. Он так же дешев, как и он, и я все еще вижу столкновение между разными файлами.
Ответ 5
Если вы можете отказаться от требования к ресурсам Linux и ограничить себя файловой системой NTFS, то альтернативные потоки данных NTFS станут идеальным решением, которое:
- не требует никакого хеширования;
- выживает переименование; и
- выживает (даже между разными томами NTFS).
Подробнее об этом можно узнать здесь. В основном вы просто добавляете двоеточие и имя для своего потока (например, ": meta" ) и пишите все, что вам нравится. Поэтому, если у вас есть каталог "D:\Movies\Terminator", напишите свои метаданные, используя стандартный ввод/вывод файлов, в "D:\Movies\Terminator: meta". Вы можете сделать то же самое, если хотите сохранить метаданные для определенного файла (в отличие от целой папки).
Если вы предпочитаете хранить свои метаданные где-то в другом месте и просто сможете обнаруживать перемещения/переименования на том же томе NTFS, вы можете использовать вызов API GetFileInformationByHandle (см. MSDN/en-us/library/aa364952 (VS. 85).aspx), чтобы получить уникальный идентификатор папки (объединить члены VolumeSerialNumber и FileIndex). Этот идентификатор не изменится, если файл/папка перемещена/переименована на том же томе.
Ответ 6
Ну, сначала вам нужно глубже изучить, как работают файловые системы. С какими файловыми системами вы будете работать? Большинство файловых систем поддерживают такие вещи, как жесткие ссылки и софт-ссылки, поэтому информация "filename" не обязательно сохраняется в метаданных самого файла.
Собственно, это весь смысл многоуровневой файловой системы с многослойной структурой, которую вы можете распространять по-разному, скажем, для поддержки сжатия или шифрования. Это то, о чем "вноды". Вы могли бы сделать это несколькими способами. Некоторые из них очень зависят от платформы, на которую вы смотрите. Это намного проще в системах UNIX/Linux, использующих концепцию VFS. Вы можете реализовать свой собственный слой на диске ext3, например, или что у вас есть.
**
После прочтения ваших изменений, couplre больше вещей. Файловые системы уже делают это, как упоминалось ранее, с помощью таких вещей, как inodes. Хеширование, вероятно, будет плохой идеей не только потому, что это дорого, но потому, что два или более прообразов могут использовать один и тот же образ; то есть два совершенно разных файла могут иметь одно и то же значение хэширования. Я думаю, что вы действительно хотите использовать метаданные того, что уже предоставляет файловая система. Конечно, это было бы проще в системе с открытым исходным кодом.:)
Ответ 7
Какие байты я должен выбрать для образца?
Я думаю, что я попытаюсь использовать некоторую арифметическую прогрессию, такую как числа Фибоначчи. Их легко вычислить, и они имеют уменьшающуюся плотность. Маленькие файлы будут иметь более высокий коэффициент выборки, чем большие файлы, и образец будет по-прежнему перемещаться по пятнам во всем файле.
Ответ 8
Эта работа звучит так, что ее можно было бы более эффективно реализовать на уровне файловой системы или с некоторой свободной аппроксимацией системы управления версиями (оба?).
Чтобы решить исходный вопрос, вы можете сохранить базу данных (размер файла, хэширование байтов, хеш) для каждого файла и попытаться свести к минимуму количество байтов, хэшированных для каждого размера файла. Всякий раз, когда вы обнаруживаете столкновение, у вас либо есть идентичный файл, либо вы увеличиваете длину хэша, чтобы пройти мимо первой разницы.
Там, несомненно, будут сделаны оптимизации и компромиссы между процессорами и I/O, но это хорошее начало для чего-то, что не будет иметь ложных срабатываний.