Что нового

Как сравнить два файла ?

vaf

Новичок
Сообщения
189
Репутация
2
Всем привет - возникла потребность сравнивать два файла. Написал такой незамысловатый код, но если небольшие файлы он сравнивает быстро, то несколько мегабайт уходит целая вечность.
Не подскажете как можно относительно быстро сравнить два файла ? Может быть есть какая то библиотека которая контрольные суммы считает ?

Код:
Func _FileCompare($File1, $File2)
    Local $hFile1 = FileOpen($File1, 16)
    Local $hFile2 = FileOpen($File2, 16)
    If $hFile1 = -1 Or $hFile2 = -1 Then
        Return False
    EndIf
    Local $bEqual = True
    While True
        Local $byte1 = FileRead($hFile1, 1)
        Local $byte2 = FileRead($hFile2, 1)
        If $byte1 <> $byte2 Then
            $bEqual = False
            ExitLoop
        EndIf
        If @error Then ExitLoop
    WEnd
    FileClose($hFile1)
    FileClose($hFile2)
    Return $bEqual
EndFunc
 

IMStrelcov

CTPEJIbLLOB
Сообщения
258
Репутация
66
Код:
Func _FileCompare($sFile1, $sFile2)
    Local $sMd5_1 = CheckSumMD5_File_($sFile1)
    Local $sMd5_2 = CheckSumMD5_File_($sFile2)
    Return ($sMd5_1 = $sMd5_2)
EndFunc

;###################################################################################################
; Описание:       вычисляет контрольную сумму файла
;===================================================================================================
; Синтаксис:      CheckSumMD5_File_($_sFile)
;===================================================================================================
; Параметры:      $_sFile = путь к файлу
;===================================================================================================
; Результат:      возвращает контрольную сумму
;===================================================================================================
; Примечание:     ?
;###################################################################################################
Func CheckSumMD5_File_($_sFile)
   Local $_iError = 1, $_sMD5 = '0x00'
   Local $_aFile = DllCall('kernel32.dll', 'hwnd', 'CreateFileW', 'wstr', $_sFile, 'dword', 0x80000000, 'dword', 3, 'ptr', 0, 'dword', 3, 'dword', 0, 'ptr', 0)
   If Not @error And ($_aFile[0] <> -1) Then
      Local $_aMapping = DllCall('kernel32.dll', 'ptr', 'CreateFileMappingW', 'hwnd', $_aFile[0], 'dword', 0, 'dword', 2, 'dword', 0, 'dword', 0, 'ptr', 0)
      If Not @error And $_aMapping[0] Then
         Local $_tContext = DllStructCreate('dword i[2];dword buf[4];ubyte in[64];ubyte digest[16]')
         Local $_pContext = DllStructGetPtr($_tContext)
         DllCall('advapi32.dll', 'none', 'MD5Init', 'ptr', $_pContext)
         If Not @error Then
            Local $_iBufferSize = 1048576 * 8;8Mb.
            Local $_iFileSize = FileGetSize($_sFile)
            Local $_iFilePos, $_aMapView
            For $_iFilePos = 0 To $_iFileSize Step $_iBufferSize
               If ($_iFilePos + $_iBufferSize) > $_iFileSize Then $_iBufferSize = $_iFileSize - $_iFilePos
               $_aMapView = DllCall('kernel32.dll', 'ptr', 'MapViewOfFile', 'hwnd', $_aMapping[0], 'dword', 4, 'dword', HiDWord_($_iFilePos), 'dword', LoDWord_($_iFilePos), 'dword', $_iBufferSize)
               If Not @error And $_aMapView[0] Then
                  DllCall('advapi32.dll', 'none', 'MD5Update', 'ptr', $_pContext, 'ptr', $_aMapView[0], 'dword', $_iBufferSize)
                  $_iError = @error
                  DllCall('kernel32.dll', 'int', 'UnmapViewOfFile', 'ptr', $_aMapView[0])
                  If $_iError Then ExitLoop
               EndIf
            Next
            DllCall('advapi32.dll', 'none', 'MD5Final', 'ptr', $_pContext)
            If Not @error Then $_sMD5 = '0x'& Hex(DllStructGetData($_tContext, 'digest'))
         EndIf
         DllCall('kernel32.dll', 'int', 'CloseHandle', 'hwnd', $_aMapping[0])
      EndIf
      DllCall('kernel32.dll', 'int', 'CloseHandle', 'hwnd', $_aFile[0])
   EndIf
   Return SetError($_iError, 0, $_sMD5)
EndFunc

Func HiDWord_($_iValue)
   Local $_tInt64 = DllStructCreate('int64')
   Local $_tQWord = DllStructCreate('dword;dword', DllStructGetPtr($_tInt64))
   DllStructSetData($_tInt64, 1, $_iValue)
   Return DllStructGetData($_tQWord, 2)
EndFunc

Func LoDWord_($_iValue)
   Local $_tInt64 = DllStructCreate('int64')
   Local $_tQWord = DllStructCreate('dword;dword', DllStructGetPtr($_tInt64))
   DllStructSetData($_tInt64, 1, $_iValue)
   Return DllStructGetData($_tQWord, 1)
EndFunc
 
Последнее редактирование:

Alecsis

Осваивающий
Сообщения
101
Репутация
41
Добавлю свои «5 копеек»
Код:
Func _FileCompare($File1, $File2)
    Local Const $sFmtCmd = 'cmd /c fc.exe /b "%s"  "%s" >nul' ; шаблон команды двоичного сравнения
    Local $bEqual = False
    Local $sCommand, $iRC

    ; оба файла должны существовать
    ;
    If Not FileExists($File1) Or Not FileExists($File2) Then
      ConsoleWrite('Нет как min одного из файлов' & @CRLF)
      Return SetError(1, 0, False)  ; нечего сравнивать
    EndIf

    ; оба файла д.б. одного размера
    ;
    If Not (FileGetSize($File1) = FileGetSize($File2)) Then
      ConsoleWrite('Файлы разного размера' & @CRLF)
      Return False    ; нет смысла сравнивать
    EndIf

    ; не изобретаем велосипед, а задействуем штатную утилиту Wind-ы fc.exe
    ; её код возврата = 0 если файлы равны, иначе ненулевой
    ;
    $iRC = RunWait (StringFormat($sFmtCmd, $File1, $File2), '', @SW_HIDE)
    $bEqual = ($iRC = 0)  ;
    Return $bEqual
EndFunc

PS в архиве примитивный тестовый скрипт + файлы-«подопытные кролики»
 

Вложения

  • FComp.rar
    1 КБ · Просмотры: 1

Eugen_pcad_ru

Новичок
Сообщения
7
Репутация
0
Всем привет - возникла потребность сравнивать два файла. Написал такой незамысловатый код, но если небольшие файлы он сравнивает быстро, то несколько мегабайт уходит целая вечность.
Не подскажете как можно относительно быстро сравнить два файла ? Может быть есть какая то библиотека которая контрольные суммы считает ?

Код:
Func _FileCompare($File1, $File2)
    Local $hFile1 = FileOpen($File1, 16)
    Local $hFile2 = FileOpen($File2, 16)
    If $hFile1 = -1 Or $hFile2 = -1 Then
        Return False
    EndIf
    Local $bEqual = True
    While True
        Local $byte1 = FileRead($hFile1, 1)
        Local $byte2 = FileRead($hFile2, 1)
        If $byte1 <> $byte2 Then
            $bEqual = False
            ExitLoop
        EndIf
        If @error Then ExitLoop
    WEnd
    FileClose($hFile1)
    FileClose($hFile2)
    Return $bEqual
EndFunc
1 Проще всего сравнить MD5 файлов, как уже было предложено выше.
2 Можно использовать внешнюю утилиту: https://sourceforge.net/projects/swissfileknife/
 
Верх