2014-01-28 5 views
0

У меня есть следующая ситуация в C#:Какой лучший способ сравнить 2 файла?

ZipFile z1 = ZipFile.Read("f1.zip"); 
ZipFile z2 = ZipFile.Read("f2.zip"); 


MemoryStream ms1 = new MemoryStream(); 
MemoryStream ms2 = new MemoryStream() 


ZipEntry zipentry1 = zip1["f1.dll"]; 
ZipEntry zipentry1 = zip2["f2.dll"]; 


zipentry1.Extract(ms1); 
zipentry2.Extract(ms2); 


byte[] b1 = new byte[ms1.Length]; 
byte[] b2 = new byte[ms2.Length]; 


ms1.Seek(0, SeekOrigin.Begin); 
ms2.Seek(0, SeekOrigin.Begin); 

, что я сделал здесь открыт 2 почтовые файлы f1.zip и f2.zip. Затем я извлекаю из них 2 файла (f1.txt и f2.txt внутри f1.zip и f2.zip соответственно) на объекты MemoryStream. Теперь я хочу сравнить файлы и выяснить, являются ли они одинаковыми или нет. У меня было 2 способа:

1) Прочитайте байты памяти байтами по байтам и сравните их. Для этого я хотел бы использовать

ms1.BeginRead(b1, 0, (int) ms1.Length, null, null); 
ms2.BeginRead(b2, 0, (int) ms2.Length, null, null); 

, а затем запустить цикл и сравнить каждый байт в b1 и b2.

2) Получите строковые значения для обоих потоков памяти, а затем выполните сравнение строк. Для этого я бы использовал

string str1 = Encoding.UTF8.GetString(ms1.GetBuffer(), 0, (int)ms1.Length); 
string str2 = Encoding.UTF8.GetString(ms2.GetBuffer(), 0, (int)ms2.Length); 

, а затем сделать простую строку сравнения.

Теперь я знаю, что сравнение байта по байт всегда даст мне правильный результат. Но проблема с этим - это займет много времени, поскольку я должен сделать это для тысяч файлов. Вот почему я думаю о методе сравнения строк, который пытается выяснить, равны ли файлы или не очень быстро. Но я не уверен, что сравнение строк даст мне правильный результат, так как файлы являются либо dll, либо медиафайлами и т. Д., И обязательно будут содержать специальные символы.

Может ли кто-нибудь сказать мне, будет ли метод сравнения строк работать правильно или нет?

Заранее спасибо.

P.S. : Я использую DotNetLibrary.

+0

Сравнение строк будет МНОГО медленнее, чем сравнение байтов. – Magus

+0

, но число байтов больше 50000. Таким образом, цикл for более 50000 будет медленнее, чем сравнение строк? – user2945623

+0

@ user2945623 Нет. Уверен, что ваша машина завершит этот цикл так быстро, что вы даже не заметите. –

ответ

2

Базовая линия для этого вопроса - это родной способ сравнения массивов: Enumerable.SequenceEqual. Вы должны использовать это, если у вас нет оснований для этого.

Если вам нужна скорость, вы можете попытаться выполнить p/invoke на memcmp в msvcrt.dll и сравнить массивы байтов таким образом. Мне трудно представить, что можно избить. Очевидно, что вы сначала проверили бы сравнение длин и позвонили бы только memcmp, если бы два байтовых массива имели одинаковую длину.

P/Invoke выглядит следующим образом:

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)] 
static extern int memcmp(byte[] lhs, byte[] rhs, UIntPtr count); 

Но вы должны созерцать это, только если вы действительно заботиться о скорости, а также чистые управляемые альтернативы слишком медленно для вас. Итак, сделайте некоторые тайминги, чтобы убедиться, что вы не оптимизируете преждевременно. Ну, даже чтобы убедиться, что вы оптимизируете вообще.

Я был бы очень удивлен, если бы преобразование в string было быстрым. Я ожидаю, что это будет медленным. И на самом деле я ожидаю, что ваш код не сработает, потому что нет никаких оснований для того, чтобы ваши байтовые массивы были действительными UTF-8. Просто забывай, что у тебя была эта идея!

+0

получил. большое спасибо. – user2945623

+0

Правильный тип 'count' -' UIntPtr'. 'ulong' не будет работать на 32-битных системах. –

+0

@CoryNelson Спасибо. Вы, конечно, совершенно правы. Это 'size_t'. Не знаю, что случилось со мной. –

2

Сравнить ZipEntry.Crc и ZipEntry.UncompressedSize из двух файлов, только, если они соответствуют распаковывать и сделать сравнение байтов. Если оба файла одинаковы, их CRC и Size будут одинаковыми. Эта стратегия избавит вас от тонны циклов процессора.

ZipEntry zipentry1 = zip1["f1.dll"]; 
ZipEntry zipentry2 = zip2["f2.dll"]; 

if (zipentry1.Crc == zipentry2.Crc && zipentry1.UncompressedSize == zipentry2.UncompressedSize) 
{ 
    // uncompress 
    zipentry1.Extract(ms1); 
    zipentry2.Extract(ms2); 

    byte[] b1 = new byte[ms1.Length]; 
    byte[] b2 = new byte[ms2.Length]; 

    ms1.Seek(0, SeekOrigin.Begin); 
    ms2.Seek(0, SeekOrigin.Begin); 

    ms1.BeginRead(b1, 0, (int) ms1.Length, null, null); 
    ms2.BeginRead(b2, 0, (int) ms2.Length, null, null); 

    // perform a byte comparison 
    if (Enumerable.SequenceEqual(b1, b2)) // or a simple for loop 
    { 
     // files are the same 
    } 
    else 
    { 
     // files are different 
    } 
} 
else 
{ 
    // files are different 
} 
+0

+1 Это очень здравый совет. Отклонить различные файлы как можно скорее. –

Смежные вопросы