Чи потрібно читати кожен байт, щоб перевірити, чи скопійований файл ідентичний оригіналу?


16

Нещодавно я дізнався про програму під назвою Total Commander. Це заміна Windows Explorer і має власні речі для копіювання файлів. Щоб перевірити, чи файли однакові, замість обчислення CRC, він буквально перевіряє кожен байт, по одному, як на оригінал, так і на копію.

Моє запитання: чи потрібно це? Чи може CRC чи будь-яка інша така техніка піти не так? Чи варто вам, як програмісту, спробувати реалізувати цю ідеальну, але повільну систему, чи це занадто екстремально?


3
Погляньте, як "rsync" справляється з цим.

21
Обчислення CRC (або, краще, sha1sums) для обох файлів вимагає читання кожного байта в будь-якому випадку. Якщо ви робите порівняння байт-байт, ви можете вийти з роботи, як тільки побачите невідповідність - і вам не доведеться турбуватися про два різні файли, які, мабуть, мають однакову контрольну суму (хоча це шансуальне навряд чи) . З іншого боку, порівняння контрольної суми корисно при порівнянні файлів, які не знаходяться на одній машині; контрольні суми можна обчислити локально, і вам не потрібно передавати весь вміст по мережі.
Кіт Томпсон

3
Що стосується ймовірності зіткнення, якщо ви використовуєте пристойний хеш на кшталт, який sha1sumви любите, вам не доведеться хвилюватися з цього приводу, якщо хтось навмисно і дорого не створює файли, чиї sha1sums стикаються. У мене немає джерела для цього, але я чув (у контексті git), що ймовірність двох різних файлів, що мають однаковий sha1sum, приблизно така ж, як ймовірність того, що кожен член вашої команди розробників буде з'їдений вовки. Того ж дня. У абсолютно незв’язаних інцидентах.
Кіт Томпсон

5
@KeithThompson: Я думаю, що ваш перший коментар повинен бути відповіддю :-)
Дін Хардінг

6
Коротка відповідь - Ні, найкраще просто зробити так, щоб ваш комп’ютер зробив це за вас.
пн.

Відповіді:


40

Обчислення CRC (або, краще, sha1sums) для обох файлів вимагає читання кожного байта в будь-якому випадку. Якщо ви робите порівняння байт-байт, ви можете вийти з роботи, як тільки побачите невідповідність - і вам не доведеться турбуватися про два різні файли, які, мабуть, мають однакову контрольну суму (хоча це шансуальне навряд чи) . Отже, якщо ви робите порівняння локально, порівняння байт-байт буде принаймні таким же швидким, як порівняння контрольної суми (якщо ви все-таки не розрахували контрольні суми).

З іншого боку, порівняння контрольної суми корисно при порівнянні файлів, які не знаходяться на одній машині; контрольні суми можна обчислити локально, і вам не потрібно передавати весь вміст по мережі.

Можливі також гібридні підходи. Наприклад, ви можете обчислити та порівняти контрольні суми для двох файлів одночасно, що дозволяє уникнути читання цілих файлів ( якщо вони відрізняються), уникаючи передачі всього файлу по мережі. Протокол rsync робить щось подібне.

Зауважте, що використання простої CRC дає вам шанси на зіткнення, про що Дейв Реджер згадував у своїй відповіді. Використовуйте принаймні sha1sum або навіть щось більш сучасне. (Не намагайтеся вигадувати свій власний алгоритм хешування; люди, які розробили sha1sum, знають набагато більше про ці речі, ніж хтось із нас.)

Що стосується ймовірності зіткнення, якщо ви використовуєте пристойний хеш, наприклад, sha1sum, вам майже не потрібно про це турбуватися, якщо хтось навмисно і дорого не створює файли, чиї sha1sums стикаються (генерування таких зіткнень було неможливим, коли я вперше написав це , але прогрес досягається ). Цитуючи "Pro Git" Скотта Чакона , розділ 6.1 :

Ось приклад, щоб дати вам уявлення про те, що знадобиться для зіткнення SHA-1. Якби всі 6,5 мільярдів людей на Землі програмували, і щосекунди кожен виробляв код, який був еквівалентом всієї історії ядра Linux (1 мільйон об'єктів Git) і переміщував її в одне величезне сховище Git, це займе 5 років, поки це сховище містило достатньо об'єктів, щоб мати 50% -ву ймовірність зіткнення одного об'єкта SHA-1. Існує більша ймовірність того, що в один і той же вечір кожен член вашої команди програмування буде нападений і убитий вовками в неспоріднених інцидентах.

Підсумок:

Байт-байтове порівняння добре для місцевих порівнянь. sha1sum хороший для віддаленого порівняння і не має значних шансів на помилкові позитиви.


Слід зазначити, що загальне визначення "хорошої" хеш-функції включає властивість, що дуже важко створювати різні входи з однаковим хешем ("стійкість до зіткнення"). У цьому відношенні SHA-1 має деякі (поки що теоретичні) недоліки, але ви не можете просто "сконструювати два файли, які стикаються", навіть якщо ви дуже стараєтесь.
sleske

@sleske: Оновлено
Кіт Томпсон

1
@KeithThompson Я підтримую відповідь, але думаю, що прийшов час для оновлення програми SHA1 - The SHAppening
K.Steff

Я підозрюю, що вони отримають каприз, якщо ви спробуєте влаштувати це теоретичне репо на GitHub.
hBy2Py

1
Я більше мав на увазі, що вони будуть незадоволені тим, що в них, однак, є багато екскаваторів в секунду. :-)
hBy2Py

10

Ось ще один спосіб подумати про це.

Якщо немає можливості, що два різні файли мають один і той же CRC, то за допомогою розширення це означає, що кожен файл може бути представлений унікальною CRC. Якщо CRC був меншим, ніж вихідний файл, то він представляв би форму стиснення без втрат. Якщо ні, то ви б так само добре порівняли оригінальні файли, оскільки ви порівнювали б однакову кількість байтів.

Теоретично ви можете використовувати стиснення без втрат обох сторін порівняння, щоб зменшити кількість байтів, необхідних для порівняння, але це дурень, тому що ви витрачаєте більше циклів і вам доведеться читати кожен байт обох файлів, щоб зробити стиснення. . Тобто, щоб кодувати кожен байт (і це порядок) у схемі стиснення без втрат, потрібно було б спершу його прочитати та підключити до алгоритму, правда? Гра завершена.

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


3

Єдиний ідеальний спосіб перевірити наявність однакових файлів - це байт для порівняння байтів. Інший спосіб бути справедливим наближенням - обчислити хеш, такий як MD5, для файлів та порівняти їх. Можливо, може статися хеш-зіткнення, але це не дуже ймовірно.

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

CRC, мабуть, не такий шлях, оскільки це лише механізм виявлення помилок, а не хеш. (або поганий хеш із великою кількістю можливих зіткнень)


+1 Згоден. Це набагато більше шансів на те, що ваш жорсткий диск зламається порівняно з випадковим зіткненням гарної функції хешування (CRC32 слабкий - теж згоден).
Міхал Шрайер

2

Щоб бути на 100% певними, два файли однакові, вам дійсно потрібно перевірити байти.

Чому? Хеш-зіткнення, ось чому! Залежно від алгоритму, що використовується для хешування, зіткнення може бути більш-менш ймовірним, але можливо все-таки. Виконуючи ці дії:

  1. Перевірте розміри файлів
  2. Перевірте типи мім
  3. Перевірте хеш
  4. Перевірте кілька випадкових зсувів і порівняйте біти

Дасть вам дуже високу гарантію впевненості, що два файли однакові, однак є дуже (надзвичайно) невеликий шанс, що у вас зіткнення на руках. Вибір того, як далеко ви хочете пройти зі своїми порівняннями, буде продиктований ситуацією.


Я думаю, якщо вибрати хороший алгоритм хешування, 2 і 4. не дадуть тобі жодного реального підвищення "рівної" якості. Ймовірно, 1. потрібен лише для слабкого хешу.
Michał Šrajer

1
-1 Це не має сенсу. Якщо вибрати хороший алгоритм хешування, всі інші кроки зайві. 1. і 4. насправді вже охоплені тим, що робить хеш, і 2. - це нісенітниця (більшість файлових систем навіть не мають поняття "тип MIME", і навіть якщо вони були, це додає дуже мало інформації).
sleske

@sleske Я говорю, що замість того, щоб вирівнювати хеш-файл, це інтенсивні операції, ви можете виконати деякі попередні операції, які не такі важкі.

Я повторюю, що лише 1 і 3 мають багато сенсу. (1) позначить більшість випадків різних файлів, зберігаючи необхідність обчислити хеш. Хеш-зіткнення файлу однакової довжини настільки малоймовірне, що його не варто турбувати.
Майкл Шов

1

Як говорили інші, швидше зробити порівняння байт-байт, якщо два файли є в одній системі. Якщо ви намагаєтеся порівняти купу файлів, ви досягнете точки, коли хеш - це краща відповідь, якщо вони знаходяться у спінінг-накопичувачі.

Хешинг справді світить, коли у вас немає всіх доступних даних. Наприклад, файли знаходяться на різних машинах. Це також дозволяє зберегти результати обчислень і звернутися до них пізніше. (Чи є цей звіт таким же, як і старий? Коли ви робите звіт, збережіть хеш. Коли ви робите наступний, ви можете просто порівняти хеші. Мало того, що вам не потрібно читати старий у вашому доні " t навіть необхідна наявність його копії.)


0

Я думаю, що ви повинні використовувати надану утиліту порівняння файлів з вашою операційною системою або використовувати інструмент порівняння файлів (див. Інструменти порівняння файлів вікі-файлів ) для порівняння вмісту ПІСЛЯ ви перевірили властивості файлу, окреслені @Glenn Nelson.

Я не думаю, що CRC є на 100% точним, і я думаю, що його точність зменшується з довжиною файлу. Також я не пропоную писати це з нуля, оскільки це може зажадати багато тестування.


0

Чи потрібно читати кожен байт, щоб перевірити, чи скопійований файл ідентичний оригіналу? ТАК бути 100% впевненим

Чи потрібно читати кожен байт, щоб перевірити, чи скопійований файл НЕ ідентичний оригіналу? НІ

Таким чином, для швидкого визначення неідентичності спочатку перевірте метадані, такі як розмір файлу та будь-яку контрольну суму / CRC або MIME тип, які ОС / файлова система / зберігання вже можуть підтримувати . Оскільки вони попередньо розраховуються цією системою, ви не оплачуєте цю вартість під час порівняння.

Якщо цей тест проходить, вам все одно потрібно порівнювати кожен байт окремо, якщо вам потрібно бути впевненим на 100%, АЛЕ зауважте, що в сучасних конвеєрних процесорах і за допомогою декількох потоків і, можливо, декількох процесорів / процесорів, блокове порівняння великих файлів дійсно швидко і ефективний, оскільки процес є дуже паралельним. Швидше, ніж БУДЬ-який вид математичних обчислень, що включають кожен байт (хоча деякі алгоритми, можливо, теж паралелізуються, але, можливо, не так легко чи так добре). Це тому, що процесори, які є конвеєрним процесом, можуть виконувати операції порівняння блоків пам'яті в мікрокоді або навіть апаратному (дуже швидкому) та підсистемах диск-пам’ять високо оптимізовані для залучення величезних блоків файлів до / з пам'яті, все це робиться паралельно і з обладнання. Якщо ваша програма регулярно робить подібні речі, і це відоме вузьке місце роботи, вам було б розумно реалізувати це в добре написаному багатопотоковому коді, який використовує переваги засобів паралелізації вашої ОС та обладнання (можливо, використовуйте мову, розроблену для це).

Тільки якщо ви хочете опрацювати кожен файл один раз і зробити кілька порівнянь пізніше (де ви пам’ятаєте [«кеш»] узагальненого або «стислого» [як каже JohnFX] результату аналізу), це буде суттєвою користю для цього, і навіть тоді, лише щоб довести різницю (ймовірно); щоб підтвердити ідентичність, вам все одно потрібно буде порівняти байт-байт.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.