Алгоритм определения идентификатора файла

Для проекта с открытым исходным кодом я пишу слой абстракции поверх файловой системы.

Этот уровень позволяет мне прикреплять метаданные и отношения к каждому файлу.

Я хотел бы, чтобы слой обрабатывал файлы, переименовывая изящно и поддерживая метаданные, если файл переименован/перемещен или скопирован.

Для этого мне понадобится механизм для вычисления идентичности файла. Очевидным решением является вычисление хэша 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, но это хорошее начало для чего-то, что не будет иметь ложных срабатываний.