Как сравнить 2 файла быстро с помощью.NET?

Вместо того, чтобы отключить ufw, можно попытаться позволить (libvirt) сеть амулета с:

sudo ufw allow from `ip addr show virbr0|tail -n 1 |cut -d' ' -f 6` to any

Работы в моем случае на Ubuntu 12.04

126
задан John Saunders 29 May 2010 в 07:07
поделиться

8 ответов

Сравнение контрольной суммы, скорее всего, будет медленнее, чем побайтовое сравнение.

Чтобы сгенерировать контрольную сумму, вам необходимо загрузить каждый байт файла, и выполнить обработку на нем. Затем вам нужно будет сделать это со вторым файлом. Обработка почти наверняка будет медленнее, чем проверка сравнения.

Что касается генерации контрольной суммы: вы можете легко сделать это с помощью классов криптографии. Вот краткий пример генерации контрольной суммы MD5 с помощью C #.

Однако контрольная сумма может быть быстрее и имеет больше смысла, если вы можете предварительно вычислить контрольную сумму «тестового» или «базового» случая. . Если у вас есть существующий файл, и вы проверяете, совпадает ли новый файл с существующим, предварительно вычисляя контрольную сумму на вашем «существующем» file будет означать, что потребуется выполнить DiskIO только один раз для нового файла. Вероятно, это будет быстрее, чем побайтовое сравнение.

111
ответ дан 24 November 2019 в 00:50
поделиться

Если файлы не слишком большие, вы можете использовать:

public static byte[] ComputeFileHash(string fileName)
{
    using (var stream = File.OpenRead(fileName))
        return System.Security.Cryptography.MD5.Create().ComputeHash(stream);
}

Сравнение хешей возможно только в том случае, если хеши полезно хранить.

(Отредактировал код на что-то намного чище.)

1
ответ дан 24 November 2019 в 00:50
поделиться

Изменить: Этот метод не работает для сравнения двоичных файлов!

В .NET 4.0 класс File имеет следующие два новых метода:

public static IEnumerable<string> ReadLines(string path)
public static IEnumerable<string> ReadLines(string path, Encoding encoding)

Это означает, что вы можете использовать:

bool same = File.ReadLines(path1).SequenceEqual(File.ReadLines(path2));
12
ответ дан 24 November 2019 в 00:50
поделиться

Единственное, что может сделать сравнение контрольных сумм немного быстрее, чем побайтовое сравнение, - это тот факт, что вы читаете один файл за раз, что несколько сокращает время поиска на диске голова. Этот небольшой выигрыш, однако, вполне может быть съеден дополнительным временем вычисления хэша.

Кроме того, сравнение контрольных сумм, конечно, может быть быстрее, только если файлы идентичны. Если это не так, побайтовое сравнение закончится на первом различии, что сделает его намного быстрее.

Вы также должны учитывать, что сравнение хэш-кода только говорит вам, что это очень вероятно что файлы идентичны. Чтобы быть на 100% уверенным, вам нужно провести побайтовое сравнение.

Если хэш-код, например, 32-битный, вам около 99. 99999998% уверен, что файлы идентичны, если хэш-коды совпадают. Это близко к 100%, но если вам действительно нужна 100% уверенность, это не так.

15
ответ дан 24 November 2019 в 00:50
поделиться

В дополнение к ответу Рида Копси :

  • В худшем случае два файла идентичны. В этом случае лучше сравнивать файлы побайтно.

  • Если два файла не идентичны, вы можете немного ускорить процесс, определив раньше, что они не идентичны.

Например, если два файла имеют разную длину, то вы знаете, что они не могут быть идентичными, и вам даже не нужно сравнивать их фактическое содержимое.

34
ответ дан 24 November 2019 в 00:50
поделиться

Самый медленный метод - это побайтовое сравнение двух файлов. Самое быстрое, что мне удалось придумать, - это аналогичное сравнение, но вместо одного байта за раз вы должны использовать массив байтов размером с Int64, а затем сравнивать полученные числа.

Вот что я пришел вверх с:

    const int BYTES_TO_READ = sizeof(Int64);

    static bool FilesAreEqual(FileInfo first, FileInfo second)
    {
        if (first.Length != second.Length)
            return false;

        if (string.Equals(first.FullName, second.FullName, StringComparison.OrdinalIgnoreCase))
            return true;

        int iterations = (int)Math.Ceiling((double)first.Length / BYTES_TO_READ);

        using (FileStream fs1 = first.OpenRead())
        using (FileStream fs2 = second.OpenRead())
        {
            byte[] one = new byte[BYTES_TO_READ];
            byte[] two = new byte[BYTES_TO_READ];

            for (int i = 0; i < iterations; i++)
            {
                 fs1.Read(one, 0, BYTES_TO_READ);
                 fs2.Read(two, 0, BYTES_TO_READ);

                if (BitConverter.ToInt64(one,0) != BitConverter.ToInt64(two,0))
                    return false;
            }
        }

        return true;
    }

В моем тестировании я смог увидеть, что этот вариант превосходит простой сценарий ReadByte () почти в 3: 1. В среднем за 1000 прогонов я получил этот метод за 1063 мс, а метод ниже (прямое побайтовое сравнение) за 3031 мс. Хеширование всегда возвращалось к секунде, в среднем около 865 мс. Это тестирование проводилось с видеофайлом размером ~ 100 МБ.

Вот методы ReadByte и хеширования, которые я использовал для сравнения:

    static bool FilesAreEqual_OneByte(FileInfo first, FileInfo second)
    {
        if (first.Length != second.Length)
            return false;

        if (string.Equals(first.FullName, second.FullName, StringComparison.OrdinalIgnoreCase))
            return true;

        using (FileStream fs1 = first.OpenRead())
        using (FileStream fs2 = second.OpenRead())
        {
            for (int i = 0; i < first.Length; i++)
            {
                if (fs1.ReadByte() != fs2.ReadByte())
                    return false;
            }
        }

        return true;
    }

    static bool FilesAreEqual_Hash(FileInfo first, FileInfo second)
    {
        byte[] firstHash = MD5.Create().ComputeHash(first.OpenRead());
        byte[] secondHash = MD5.Create().ComputeHash(second.OpenRead());

        for (int i=0; i<firstHash.Length; i++)
        {
            if (firstHash[i] != secondHash[i])
                return false;
        }
        return true;
    }
127
ответ дан 24 November 2019 в 00:50
поделиться

Он становится еще быстрее, если вы не читаете маленькие 8-байтовые блоки. но поместите цикл вокруг, читая больший кусок. Я уменьшил среднее время сравнения до 1/4.

    public static bool FilesContentsAreEqual(FileInfo fileInfo1, FileInfo fileInfo2)
    {
        bool result;

        if (fileInfo1.Length != fileInfo2.Length)
        {
            result = false;
        }
        else
        {
            using (var file1 = fileInfo1.OpenRead())
            {
                using (var file2 = fileInfo2.OpenRead())
                {
                    result = StreamsContentsAreEqual(file1, file2);
                }
            }
        }

        return result;
    }

    private static bool StreamsContentsAreEqual(Stream stream1, Stream stream2)
    {
        const int bufferSize = 1024 * sizeof(Int64);
        var buffer1 = new byte[bufferSize];
        var buffer2 = new byte[bufferSize];

        while (true)
        {
            int count1 = stream1.Read(buffer1, 0, bufferSize);
            int count2 = stream2.Read(buffer2, 0, bufferSize);

            if (count1 != count2)
            {
                return false;
            }

            if (count1 == 0)
            {
                return true;
            }

            int iterations = (int)Math.Ceiling((double)count1 / sizeof(Int64));
            for (int i = 0; i < iterations; i++)
            {
                if (BitConverter.ToInt64(buffer1, i * sizeof(Int64)) != BitConverter.ToInt64(buffer2, i * sizeof(Int64)))
                {
                    return false;
                }
            }
        }
    }
}
15
ответ дан 24 November 2019 в 00:50
поделиться

Другим усовершенствованием больших файлов с одинаковой длиной может быть не чтение файлов последовательно, а сравнение более или менее случайных блоков.

Вы можете использовать несколько потоков, начиная с разных позиций в файле и сравнивая вперед или назад.

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

1
ответ дан 24 November 2019 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: