Генерация бинарных патчей на C#
Есть ли у кого-нибудь или знает о реализации алгоритма генерации бинарных патчей на C#?
По сути, сравните два файла (обозначенные как старый и новый ) и создайте файл исправления, который можно использовать для обновления старого файла, чтобы он имел то же содержимое, что и новый файл.
Реализация должна быть относительно быстрой и работать с огромными файлами. Он должен показывать время выполнения O (n) или O (logn).
Мои собственные алгоритмы имеют тенденцию быть либо паршивыми (быстрыми, но производят огромные патчи), либо медленными (производят небольшие патчи, но имеют время выполнения O (n ^ 2)).
Любые советы или указатели по реализации были бы хороши.
В частности, реализация будет использоваться для синхронизации серверов для различных больших файлов данных, для которых у нас есть один главный сервер. При изменении файлов данных главного сервера нам также необходимо обновить несколько внешних серверов.
Самый наивный алгоритм, который я сделал, который работает только с файлами, которые могут храниться в памяти, выглядит следующим образом:
- Возьмите первые четыре байта из старого файла, назовите это ключом
- Добавьте эти байты в словарь, где ключ -> позиция , где позиция - это позиция, в которой я взял эти 4 байта, 0 для начала
- Пропустите первый из этих четырех байтов, возьмите еще 4 (3 перекрытия, 1 один) и добавьте в словарь таким же образом.
- Повторите шаги 1-3 для всех 4-байтовых блоков в старом файле.
- С начала нового файла возьмите 4 байта и попытайтесь найти его в словаре.
- Если найдено, найдите самое длинное совпадение, если их несколько, сравнивая байты из двух файлов.
- Закодируйте ссылку на это место в старом файле и пропустите соответствующий блок в новом файле.
- Если не найден, закодируйте 1 байт из нового файла и пропустите его.
- Повторите шаги 5-8 для остальной части нового файла.
Это чем-то похоже на сжатие без использования окон, поэтому для этого потребуется много памяти. Однако это довольно быстро и производит довольно маленькие патчи, если я стараюсь сделать вывод кода минимальным.
Алгоритм с более эффективным использованием памяти использует окна, но производит файлы исправлений гораздо большего размера.
В описанном выше алгоритме есть больше нюансов, которые я пропустил в этом посте, но при необходимости я могу опубликовать более подробную информацию. Однако я чувствую, что мне нужен совсем другой алгоритм, поэтому улучшение вышеупомянутого алгоритма, вероятно, не приведет меня достаточно далеко.
Изменить № 1 : Вот более подробное описание вышеуказанного алгоритма.
Сначала объедините два файла, чтобы получился один большой файл. Запомните точку разделения между двумя файлами.
Во-вторых, сделайте это, возьмите 4 байта и добавьте их позицию к шагу словаря для всего во всем файле.
В-третьих, с того места, где начинается новый файл, выполните цикл, пытаясь найти существующую комбинацию из 4 байтов и найти самое длинное совпадение. Убедитесь, что мы учитываем только позиции из старого файла или более ранние позиции в новом файле, чем сейчас . Это гарантирует, что мы можем повторно использовать материал как в старом, так и в новом файле во время применения патча.
Редактировать # 2 : Исходный код вышеуказанного алгоритма
Вы можете получить предупреждение о проблемах с сертификатом. Я не знаю, как это решить, поэтому пока просто примите сертификат.
Источник использует множество других типов из остальной части моей библиотеки, так что этот файл - это не все, что нужно, но это реализация алгоритма.
@lomaxx, я попытался найти хорошую документацию по алгоритму, используемому в Subversion, который называется xdelta, но если вы еще не знаете, как работает алгоритм, найденные мной документы не могут сказать мне то, что мне нужно знать.
А может я просто тупой ... :)
Я быстро взглянул на алгоритм с того сайта, который вы дали, и, к сожалению, его нельзя использовать. Комментарий из двоичного файла diff гласит:
Поиск оптимального набора различий требует квадратичного времени по отношению к размеру входных данных, поэтому он очень быстро становится непригодным для использования.
Однако мои потребности не оптимальны, поэтому я ищу более практичное решение.
Спасибо за ответ, добавил закладку в свои утилиты, если они мне когда-нибудь понадобятся.
Изменить №1 : Обратите внимание, я посмотрю на его код, чтобы узнать, смогу ли я найти какие-то идеи, и позже я также отправлю ему электронное письмо с вопросами, но я прочитал ту книгу, на которую он ссылается, и хотя решение подходит для поиск оптимальных решений, нецелесообразен в использовании из-за требований времени.
Изменить # 2 : я обязательно выслежу реализацию python xdelta.
Ответов (6)6
Если это для установки или распространения, рассматривали ли вы использование пакета SDK для установщика Windows? У него есть возможность исправлять двоичные файлы.
http://msdn.microsoft.com/en-us/library/aa370578(VS.85).aspx
bsdiff был разработан для создания очень маленьких исправлений для двоичных файлов. Как указано на его странице, он требует max(17*n,9*n+m)+O(1)
байтов памяти и работает во O((n+m) log n)
времени (где n
- размер старого файла, а m
- размер нового файла).
Исходная реализация находится на C, но порт C# описан здесь и доступен здесь .
Возможно, стоит проверить, что некоторые другие ребята делают в этой сфере, и не обязательно на арене C#.
Это библиотека, написанная на c #
SVN также имеет алгоритм двоичного сравнения, и я знаю, что есть реализация на python, хотя я не смог найти его с помощью быстрого поиска. Они могут подсказать вам, где улучшить собственный алгоритм.
Вы видели VCDiff ? Это часть довольно активной библиотеки Misc (последний выпуск r259, 23 апреля 2008 г.). Я не использовал его, но подумал, что стоит упомянуть.