Порівняння двох файлів у C #

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

Дякую

14
Лот думок про це, Тоз. Обов'язково прочитайте коментарі, щоб переконатися, що ви робите те, що найкраще для вашого випадку використання. Удачі!
додано Автор Random, джерело
@Boo: На ці вказує, що ви на 100% правильні.
додано Автор jason, джерело
Було б корисно дізнатися про використання справи раніше. У будь-якому випадку .. ти можеш подивитися в заголовок HTTP HTTP. Нехай веб-сервер виконує всю роботу.
додано Автор Sam Axe, джерело
Привітання хлопців, багато хороших відповідей. Я, ймовірно, використовуватиме байт за порівнянням байтів. Я поясню свою ситуацію більш детально: завантажую файли з сайту кожні 5 хв, а потім перевіряю, чи файл відрізняється від попереднього завантаженого файлу. Це буде іншим раз на день, коли я перестану завантажувати файли. Оскільки порівняння будуть такими ж, більшість часу, я вважаю, що байт, порівняння байтів, буде найкращим. Знову дякую!
додано Автор Toz, джерело

7 Відповіді

Depending on how far you're looking to take it, you can take a look at Diff.NET

Ось проста функція порівняння файлів:

// This method accepts two strings the represent two files to 
// compare. A return value of 0 indicates that the contents of the files
// are the same. A return value of any other value indicates that the 
// files are not the same.
private bool FileCompare(string file1, string file2)
{
     int file1byte;
     int file2byte;
     FileStream fs1;
     FileStream fs2;

    //Determine if the same file was referenced two times.
     if (file1 == file2)
     {
         //Return true to indicate that the files are the same.
          return true;
     }

    //Open the two files.
     fs1 = new FileStream(file1, FileMode.Open, FileAccess.Read);
     fs2 = new FileStream(file2, FileMode.Open, FileAccess.Read);

    //Check the file sizes. If they are not the same, the files 
       //are not the same.
     if (fs1.Length != fs2.Length)
     {
         //Close the file
          fs1.Close();
          fs2.Close();

         //Return false to indicate files are different
          return false;
     }

    //Read and compare a byte from each file until either a
    //non-matching set of bytes is found or until the end of
    //file1 is reached.
     do 
     {
         //Read one byte from each file.
          file1byte = fs1.ReadByte();
          file2byte = fs2.ReadByte();
     }
     while ((file1byte == file2byte) && (file1byte != -1));

    //Close the files.
     fs1.Close();
     fs2.Close();

    //Return the success of the comparison. "file1byte" is 
    //equal to "file2byte" at this point only if the files are 
    //the same.
     return ((file1byte - file2byte) == 0);
}
26
додано
Будь-яка причина для використання (file1byte - file2byte) == 0 замість простого file1byte == file2byte ?
додано Автор Juan, джерело
У цій проклятій ОС X ви не побачите весь код І , немає смужки прокрутки, яка говорить про те, що є більше коду.
додано Автор Andrei Rînea, джерело
Це не може працювати, якщо в файл змінено лише один символ. Довжина потоку буде однаковою, але зміст не однаковий. Це недійсне!
додано Автор Daniel Peñalba, джерело
Вибачте, я не хотів звучати грубим :-) Запитання сказав: "Вони мають однакові імена файлів, і вони точно такі ж розміри, коли різні". Таким чином, цей підхід є помилковим. Ми розробляємо систему керування версіями, і така реалізація може призвести до катастрофи в базі даних SCM.
додано Автор Daniel Peñalba, джерело
Використовуйте більше за допомогою !
додано Автор binki, джерело
Це було фактично витягнуте з сайту microsoft. Це робить порівняння рівності, порівняння довжини та порівняння по байтах. Я думаю, ви можете помилитися в цьому.
додано Автор James Johnson, джерело
Я б сказав, що код правильний.
додано Автор Stabledog, джерело
Код правильний, але ви повинні прокрутити вниз, щоб побачити біт, який робить байт шляхом порівняння байтів. Я припускаю, що Даніель не прокручував вниз.
додано Автор Dave Knight, джерело
@ Даніель: вибачте, щоб відновити старий пост, але чи можете ви дбати пояснити, яка проблема з кодом? Мені здається, це добре, це перевірка розміру файлу, а потім байт за байтом. Яким чином одна символьна різниця може уникнути перевірки? Gracias!
додано Автор Evaldas Bieliūnas, джерело

Мені просто цікаво, чи є швидкий спосіб зробити це без необхідності вручну вводити та читати файл.

Не зовсім.

If the files came with hashes, you could compare the hashes, and if they are different you can conclude the files are different (same hashes, however, does not mean the files are the same and so you will still have to do a byte by byte comparison).

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

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

18
додано
Не могли б Ви пояснити, чому вам потрібно буде порівняти байт для байтів, якщо хеші однакові? Чому хеші будуть однаковими, якщо дані відрізняються?
додано Автор scottm, джерело
Я не зменшив цього, не знаю, хто все це робить, але я повинен не погодитися з хешуванням. Це дійсно використовується, якщо хеш зберігається для порівняння в майбутньому. Я зробив це з файлами зображень, і швидкість вражає.
додано Автор Random, джерело
@ scottm: Оскільки нерівні файли можуть мати однакові хеші. Це принцип голубці. Скажімо, ми використовуємо md5. MD5 виробляє 128-бітний хеш файлу. Тому існує 2 ^ 128 різних хешей. Є способи більше 2 ^ 128 різних файлів. Тому, оскільки ми віднімаємо простір з більш ніж 2 ^ 128 різними значеннями до простору з значеннями 2 ^ 128, має бути зіткнення. Хеш не є унікальними підписами.
додано Автор jason, джерело
@svick: Але це точно однією з цілей для git за допомогою SHA-1! Це виявлення пошкоджень сховища, можливо, зловмисниками.
додано Автор jason, джерело
@ Заклиначі: три нулі? Ого.
додано Автор jason, джерело
@svick: Звичайно, git покладається на цю асистанцію, але вона схильна до хеш-зіткнення. Це проблема для GIT.
додано Автор jason, джерело
@Random: І я згадав, що ви можете використовувати хеші для укладання файлів нерівномірно, коли хеші нерівні, і що це вигідно, коли вони попередньо обговорюються. Якщо вони не попередньо встановлені, вони не швидше, і якщо вони рівні, нам все одно доводиться йти по байтах.
додано Автор jason, джерело
Downvoter: Поясніть.
додано Автор jason, джерело
@ Джейсон, я думаю, це потенційна проблема, але це не проблема в практиці. Якщо ви знаєте, що у вас не буде зловмисників, які намагаються зламати хеш, вам не доведеться турбуватися про зіткнення.
додано Автор svick, джерело
Якщо у вас є ті ж хеші, ви можете бути впевнені, що файли однакові. Ви маєте рацію, що потрібно абсолютно точно порівняти файли з байтом за байтом (і особливо, якщо це залежить від вашої безпеки). Але деякі системи, такі як git, покладаються на те, що два різних файли з однаковими хеш-файлами не з'являться всередині системи. Звичайно, це все передбачає хороший хеш, а не щось на кшталт GetHashCode() .
додано Автор svick, джерело

Ну, я не впевнений, чи можете ви в цьому файлі написати часові мітки. Якщо ні, то ваша унікальна альтернатива - це порівняння вмісту файлів.

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

Наступний фрагмент коду показує, як це зробити:

    public static string CalcHashCode(string filename)
    {
        FileStream stream = new FileStream(
            filename,
            System.IO.FileMode.Open,
            System.IO.FileAccess.Read,
            System.IO.FileShare.ReadWrite);

        try
        {
            return CalcHashCode(stream);
        }
        finally
        {
            stream.Close();
        }
    }

    public static string CalcHashCode(FileStream file)
    {
        MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();
        Byte[] hash = md5Provider.ComputeHash(file);
        return Convert.ToBase64String(hash);
    }

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

4
додано
Схоже, ми говоримо про те, чи є хеш ідеальним хешем чи ні. Алгоритм хешування MD5 не досконалий, тому Джейсон правий - є можливість хеш-зіткнення.
додано Автор Ben, джерело
@ Джейсон: Це лише дискусія про продуктивність. У нашому випадку ми порівнюємо дерево дисків з деревом віддаленого диску. У нас попередньо розраховані хеші як на диску, так і на віддаленому, тому наша проблема полягає тільки в порівнянні пари хешів у файлі. Також ми перерахуємо хеш, коли файл змінюється. Без сумніву, це найкращий спосіб зробити це.
додано Автор Daniel Peñalba, джерело
@ Джейсон: Ідея полягає в тому, щоб зберегти файл-хеш у будь-якому місці та скористатися ним. Так, звичайно, робити порівняння за байтами краще, якщо ви збираєтеся обчислити лише один раз.
додано Автор Daniel Peñalba, джерело
@ Даніель Пенальба: Але вам все одно доводиться йти по байтах, коли хеші дорівнюють 100% певним, що файли рівні.
додано Автор jason, джерело
@svick: так. Байт за байтом може закінчуватися рано, але хеші все-таки читають весь вміст точно так само, як міг байт-байт, і якщо хеші рівні, нам так чи інакше потрібно йти байтами-байтами.
додано Автор jason, джерело
Ні! Ви STILL повинні порівнювати байт за байтом, якщо хеші рівні. І якщо хеші нерівні, то швидше робити байт-по-байтів, тому що вони можуть рано закінчитися на першій несплачковій парі байтів, але хеш повинен пройти весь шлях через файл! Арг!
додано Автор jason, джерело
Для запису два окремих файли, що мають однакове ім'я та довжину, майже напевно (майже) мають мати два різних мітки часу. Якщо нічого іншого, для написання другої копії потрібен принаймні пару мілісекунд.
додано Автор AllenG, джерело
Якщо у вас є обидва файли, я думаю, що обчислення хешу для обох буде насправді повільніше, ніж порівнювати їх безпосередньо.
додано Автор svick, джерело

Якщо імена файлів однакові, а розмір файлів однаковий, тоді ні, неможливо дізнатися, чи вони мають інший вміст, не вивчаючи вміст.

3
додано
Ця відповідь, хоча і коротка, є (в даний час) єдиною правильною відповіддю в цій темі. Це не слід вводити в оману.
додано Автор jason, джерело
Я з Джейсоном: будь ласка, прокоментуй, коли ти проголосуєш.
додано Автор AllenG, джерело

пропускати кожен файловий потік через MD5-хешер і порівнювати хеші.

2
додано
@Jason, є також проблема, якщо файли НЕ мають однакового розміру. Я знаю, що питання говорить про файли, але припускаючи, що вони не можуть бути, ми можемо усунути перевірку цього. Обчислені хеші будуть однакового розміру.
додано Автор Random, джерело
@Boo: вражаюче. OP хоче знати, чи є файли однаковими, а не, якщо вони, ймовірно, однакові.
додано Автор jason, джерело
@ L B: Порівняння двох файлів для відмінностей не є криптографічним додатком. Ми не намагаємося перевірити, чи є два файли ймовірно однаковими, а якщо вони рівні .
додано Автор jason, джерело
@Random: Я не розумію, що ви говорите.
додано Автор jason, джерело
@ L.B: Така ж проблема стосується будь-якого алгоритму хешування. ЛИБО. Хеш займає великий простір і згортає його на невеликий простір. Кожен алгоритм хешування матиме зіткнення, і багато з них.
додано Автор jason, джерело
Hex коди d131dd02c5e6eec4693d9a0698aff95c 2fcab58712467eab4004583eb8fb7f89 55ad340609f4b30283e488832571415a 085125e8f7cdc99fd91dbdf280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e2b487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080a80d1e c69821bcb6a8839396f9652b6ff72a70 </код "і" код> d131dd02c5e6eec4693d9a0698aff95c 2fcab50712467eab4004583eb8fb7f89 55ad340609f4b30283e4888325f1415a 085125e8f7cdc99fd91dbd7280373c5b d8823e3156348f5bae6dacd436c919c6 dd53e23487da03fd02396306d248cda0 e99f33420f577ee8ce54b67080280d1e c69821bcb6a8839396f965ab6ff72a70 мають однаковий хеш md5. Вони не рівні.
додано Автор jason, джерело
Ні, це означає, що вони мають той же хеш. Це НЕ "означає, що файли однакові".
додано Автор jason, джерело
Ви не звертаєте увагу: ви STILL повинні робити байт за допомогою порівняння байтів, якщо хеші рівні. Використання хешей не менше роботи, це робота БІЛЬШЕ , оскільки вам потрібно написати байт-по-байтове порівняння AND код для використання алгоритму хешування, а логіка для використання байтів у байтах, коли хеші рівні.
додано Автор jason, джерело
Але якщо хеші рівні, вам все одно доведеться вручну прочитати файли і порівняти байт за байтом, щоб зробити висновок, що вони насправді рівні. Це НЕ менше роботи. Ви не можете усунути, а потім потрібно байт за допомогою порівняння байтів.
додано Автор jason, джерело
Це не швидше, ніж просто порівняння байтів за байтом, і вам все одно доводиться йти байтом за байтом, коли хеші рівні!
додано Автор jason, джерело
Хто буде використовувати MD5?
додано Автор L.B, джерело
@ Джейсон, я знаю, ви маєте рацію в теорії, але більшість криптографічних додатків розраховують на "унікальність" сучасних хеш-алг. Я би зробив те ж саме для порівняння файлів
додано Автор L.B, джерело
Ця розмова закінчилася.
додано Автор Sam Axe, джерело
Менше програмування. Процесори відсутні (поки що), тому хто дбає, якщо він повинен робити додаткову роботу. Сучасні процесори достатньо швидкі, щоб ви не помічали додаткову роботу, за винятком того, що ви робите багато з них за короткий проміжок часу. Але ОП не вказує на це.
додано Автор Sam Axe, джерело
@ Джейсон: яка частина "в межах статистичної ймовірності" плутає? Звичайно, є зіткнення. Імовірність зіткнення в реальній ситуації зникає дуже мала. Це не лабораторія.
додано Автор Sam Axe, джерело
Ні. Немає підстав для порівняння байтів по байте, якщо хеші рівні. Рівні хеші (у межах статистичної ймовірності) означають, що файли однакові.
додано Автор Sam Axe, джерело
Його менше роботи. І ОП висловив бажання уникнути самостійного порівняння байтів.
додано Автор Sam Axe, джерело

Якщо вони не дотримуються файлів, використовуйте інструмент порівняння, такий як KDiff або WinMerge. Буде висвітлено, вони різні.

http://kdiff3.sourceforge.net/

http://winmerge.org/

2
додано
Питання полягає в тому, як програмно порівнювати два файли в .net. Письмник пише код у C# і потребує програму, яку він пише, для порівняння двох файлів. Ймовірно, він не зацікавлений в програмі shellout або графічному інтерфейсі.
додано Автор binki, джерело

Прочитайте файл у потоці, а потім перетягніть потоку. Це має дати вам надійний результат для порівняння.

byte[] fileHash1, fileHash2;

using (SHA256Managed sha = new SHA256Managed())
{
    fileHash1 = sha.ComputeHash(streamforfile1);
    fileHash2 = sha.ComputeHash(streamforfile2);
}

for (int i = 0; (i < fileHash1.Length) && (i < fileHash2.Length); i++)
    {
        if (fileHash[i] != fileHash2[i]) 
        { 
             //files are not the same
             break; 
        }
    }
0
додано
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug