Что нового

Как найти скрипту своего двойника (дубликата)

StarEdik

Новичок
Сообщения
365
Репутация
4
Как вы думаете, скрипт может найти своего дубликата (двойника, копию) на диске. :scratch: Помогите при написании скрипта. :-[
В теле скрипта имеется запись (ID, ISBN, уникальный текст, и.т.д) для идентификации. По этой записи нужно найти двойника во всех локальных дисках. Скрипт должен проверят ехешники которые написаны на Autoit-е, посылат им запрос, получит ответ. И при нахождении двойников (при получении положительного ответа )переместит их в отдельную папку. Копии в именах не совпадают.
 

beliy

Продвинутый
Сообщения
372
Репутация
72
Мне кажется что проще искать двойников по контрольной сумме. Например так:

Код:
#include <Crypt.au3>
#include<file.au3>
#include<array.au3>
#include<FileOperations.au3> ; http://www.autoitscript.com/forum/topic/133224-filesearch-foldersearch/
Global $sFldr, $aFiles, $etalonHash = '0x6F60359EC990DC048AC7446DA804AF24' ; MD5 файла с которым нужно сравнивать
$sFldr = FileSelectFolder("Укажите папку с которой нужно начать поиск:", @ScriptDir, 2) & "\"
$aFiles=_FO_FileSearch($sFldr, 'exe', True, 125, 1, 1, 0)
_ArrayDisplay($aFiles)
_Crypt_Startup()
For $i = 1 To UBound($aFiles) -1
	  If ((_Crypt_HashFile($aFiles[$i],$CALG_MD5)) == $etalonHash) Then 
        MsgBox(4096, "Найдет дубликат файла", "Дубликат: " & @CRLF & $aFiles[$i])
    EndIf
Next
_Crypt_Shutdown()
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
beliy
Нахождение контрольных сумм это длительный процесс, придётся перечитать весь диск, а это займёт 4 часа. Проще сначала найти файлы одинакового размера, а уж потом из них вычислять контрольные суммы. Да и вообще вроде StringCompare должна в разы быстрее сравнить, чем вычисление контрольных сумм.
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
StarEdik
как то так
Код:
$sPath1 = @ScriptDir&'\file1.exe'
$sPath2 = @ScriptDir&'\file2.exe'

$hFile = FileOpen($sPath1, 0)
$sText1 = FileRead($hFile)
FileClose($hFile)

$hFile = FileOpen($sPath2, 0)
$sText2 = FileRead($hFile)
FileClose($hFile)

$err = 0
$timer = TimerInit()
For $i = 1 To 100
	If StringCompare($sText1, $sText2, 1) Then
		$err += 1
	Else
		$err -= 1
	EndIf
Next
MsgBox(0, $err, 'Время : ' & Round(TimerDiff($timer), 2) & ' мсек')



Код:
#include<FileOperations.au3>
#include <Array.au3>

$iFileSize = FileGetSize(@AutoItExe)
$sPath = @ScriptDir
$aFileList = _FO_FileSearch($sPath) ; получаем список файлов
$j = 0
For $i = 1 To $aFileList[0]
	$iSizeTmp = FileGetSize($aFileList[$i])
	If $iSizeTmp = $iFileSize Then
		$j += 1
		$aFileList[$j] = $aFileList[$i]
	EndIf
Next
If $i Then
	ReDim $aFileList[$j + 1]
	$aFileList[0] = $j
Else
	Exit MsgBox(0, 'Сообщение', 'не найдено')
EndIf

_ArrayDisplay($aFileList)

$iCount = 0
$sText1 = FileRead(@AutoItExe)
For $i = 1 To $aFileList[0]
	$sText2 = FileRead($aFileList[$i])
	If $sText1 == $sText2 Then
		$iCount += 1
	EndIf
Next
MsgBox(0, 'Сообщение', 'Найдено ' & $iCount)
 

beliy

Продвинутый
Сообщения
372
Репутация
72
Переделал свой скрипт с учетом замечаний от AZJIO. Теперь сравнение происходит, только если размер и версия файла совпадают с эталонным скриптом. Можно переделать через поиск уникальных записей в скрипте (ID, ISBN, уникальный текст, и.т.д), но очень мало информации о том в каком виде хранятся эти данные. В любом случае переделать сравнение файлов на базе существующего скрипта не должно составить труда.
Код:
#include <Crypt.au3> 
#include<file.au3>
#include<array.au3>
#include<FileOperations.au3> ; http://www.autoitscript.com/forum/topic/133224-filesearch-foldersearch/
Global $sFldr, $aFiles
$sFldr = FileSelectFolder("Укажите папку с которой начать поиск:", @ScriptDir, 2) & "\"
$aFiles=_FO_FileSearch($sFldr, 'exe', True, 125, 1, 1, 0)
;_ArrayDisplay($aFiles)
 $sEtalonSize = FileGetSize(@ScriptFullPath)
 $sEtalonVer = FileGetVersion(@ScriptFullPath)
_Crypt_Startup()
$etalonHash = _Crypt_HashFile(@ScriptFullPath ,$CALG_MD5) ; MD5
For $i = 1 To UBound($aFiles) -1
   If (FileGetSize($aFiles[$i]) == $sEtalonSize) AND (FileGetVersion($aFiles[$i]) == $sEtalonVer) Then
	  If ((_Crypt_HashFile($aFiles[$i],$CALG_MD5)) == $etalonHash) Then 
        MsgBox(4096, "Найдет дубликат файла", "Дубликат: " & @CRLF & $aFiles[$i])
	  EndIf
	EndIf
Next
_Crypt_Shutdown()


2 AZJIO
возможны ли проблемы при сравнении файлов больших размеров через StringCompare? Если да, то какой максимальный размер файла для данного способа?
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
beliy [?]
возможны ли проблемы при сравнении файлов больших размеров через StringCompare? Если да то какой максимальный размер файла для данного способа?
Я пока использовал обычное сравнение "==", потому что с бинарными данными, несмотря что я их преобразовал в строки, мне так и не удалось получить валидного результата (я забыл, что при совпадении возвращает 0). На счёт размера - надо тестировать. Естественно большие файлы в память не поместятся, а значит нужно читать частями и сравнивать каждую часть отдельно.
У меня даже в этом плане со вчерашнего дня появилась идея изменения программы поиска дубликатов в связи с тем что вычисление контрольной суммы требует а) чтение файла, б) вычисление, а ведь вычисление как таковое не требуется. Отсюда вывод: ускорить эту операцию написанием функции сравнения двух файлов независимо от его длины. Хотя тут опять не всё гладко: если найдено два дубликата, то выполняется обычное сравнение байт в байт; если найдно больше дубликатов но позволяет загрузить файл в память, то опять сравниваем байт в байт; если найдено много дубликатов для большого файла, то вычисление контрольной суммы. Хотя для текущей задачи размер скомпилированного скрипта 300 - 1000 кб.
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
AZJIO
beliy
Спасибо. По идее скрипт (это должна быть в виде Функции) при запуске должен искать на всех локальных дисках, а не начинать с папки. Я получил список дисков из справки. Старался, но без результатно. :stars: Может поможете реализовать идею, а. :-[
Код:
Func _findcopy()
	
$var = DriveGetDrive( "all" )
If NOT @error Then
	
	For $i = 1 to $var[0]
		;MsgBox(4096,"Drive " & $i, $var[$i])
		
	Next
EndIf
	
EndFunc
 

ivsatel

Продвинутый
Сообщения
319
Репутация
84
StarEdik
Код:
#include <Array.au3> ; для _ArrayDisplay
#include <FileOperations.au3>

MsgBox('','', @ScriptName)

_findcopy()

Func _findcopy()

$var = DriveGetDrive( "FIXED" )

For $i = 1 to UBound($var) - 1
	$FileList = _FO_FileSearch($var[$i], @ScriptName, True, 125, 1, 1)
	_ArrayDisplay($FileList, 'Файл')
Next
Exit
EndFunc
 

beliy

Продвинутый
Сообщения
372
Репутация
72
Чуть более универсальный вариант написания функции:

Код:
#include <Crypt.au3>
#include<file.au3>
#include<array.au3>
#include<FileOperations.au3> ; http://www.autoitscript.com/forum/topic/133224-filesearch-foldersearch/
Global $aFiles ;,$sFldr
;$sFldr = FileSelectFolder("Укажите папку с которой начать поиск:", @ScriptDir, 2) & "\"

$aDisk = DriveGetDrive ("FIXED")

For $i = 1 to UBound($aDisk) - 1
   _findcopy($aDisk[$i])
Next

Func _findcopy($dir)
   $aFiles=_FO_FileSearch($dir, 'exe', True, 125, 1, 1, 0)
   ;_ArrayDisplay($aFiles)
   $sEtalonSize = FileGetSize(@ScriptFullPath)
   $sEtalonVer = FileGetVersion(@ScriptFullPath)
   _Crypt_Startup()
   $etalonHash = _Crypt_HashFile(@ScriptFullPath ,$CALG_MD5) ; MD5
   For $i = 1 To UBound($aFiles) -1
	  If (FileGetSize($aFiles[$i]) == $sEtalonSize) AND (FileGetVersion($aFiles[$i]) == $sEtalonVer) Then
		 If ((_Crypt_HashFile($aFiles[$i],$CALG_MD5)) == $etalonHash) Then
		 MsgBox(4096, "Найдет дубликат файла", "Дубликат: " & @CRLF & $aFiles[$i])
		 EndIf
	  EndIf
   Next
   _Crypt_Shutdown()
EndFunc
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
StarEdik
Не тестировал

Код:
#include<FileOperations.au3>
#include <Array.au3>

$aFileList = _FindCopy(@AutoItExe)
Switch @error
	Case 0
		$sText = 'Найдено ' & $aFileList[0] & ' файлов дубликатов'
	Case 1
		$sText = 'Диски не найдены'
	Case 2
		$sText = 'Файлы не найдены'
	Case 3
		$sText = 'Одинаковые по размеру файлы не найдены'
	Case 4
		$sText = 'Дубликаты не найдены'
EndSwitch
MsgBox(0, 'Сообщение', $sText)
_ArrayDisplay($aFileList, 'Дубликаты')

Func _FindCopy($sPathFile)
	Local $aDrive, $iFileSize, $j, $sText1, $tmp, $vFileList

	$aDrive = DriveGetDrive('ALL')
	If @error Then Return SetError(1, 0, 0)
	$iFileSize = FileGetSize($sPathFile) ; получаем размер файла, который ищем

	$vFileList = ''
	For $i = 1 To $aDrive[0]
		; Маску можно указать "*.exe", для теста вместо 125 вписать 0, чтобы быстро найти только в корне дисков.
		$tmp = _FO_FileSearch($aDrive[$i], "*", True, 125, 1, 0) ; получаем список файлов диска.
		If Not @error Then $vFileList &= $tmp & @CRLF
	Next
	$vFileList = StringReplace($vFileList, $sPathFile & @CRLF, '') ; исключаем искомый файл из списка
	If Not $vFileList Then Return SetError(2, 0, 0) ; Если список пуст, то вылет из функции

	$vFileList = StringSplit(StringTrimRight($vFileList, 2), @CRLF, 1) ; список преобразуется в массив
	$j = 0
	For $i = 1 To $vFileList[0]
		$tmp = FileGetSize($vFileList[$i]) ; получаем размер файла в списке
		If $tmp = $iFileSize Then ; если совпадает с оригиналом, тогда
			$j += 1
			$vFileList[$j] = $vFileList[$i] ; записываем в массив
		EndIf
	Next
	If $i Then
		ReDim $vFileList[$j + 1]
		$vFileList[0] = $j
	Else
		Return SetError(3, 0, 0) ; не найдено одинаковых размеров файлов
	EndIf

	$j = 0
	$sText1 = FileRead($sPathFile) ; читаем оригинал
	For $i = 1 To $vFileList[0]
		$tmp = FileRead($vFileList[$i]) ; читаем файл в списке
		If $sText1 == $tmp Then ; если содержимое одинаково
			$j += 1 ; увеличиваем счётчик
			$vFileList[$j] = $vFileList[$i] ; записываем в массив
			; или делаем что-то ещё
		EndIf
	Next
	If $i Then
		ReDim $vFileList[$j + 1]
		$vFileList[0] = $j
		Return SetError(0, $j, $vFileList)
	Else
		Return SetError(4, 0, 0) ; не найдено дубликатов
	EndIf
EndFunc   ;==>_FindCopy


Кстати, у вас примеры из старомодной справки.

beliy
Я создал тему на офсайте, посмотрим ответы. Сравнил файл размером 46 Мб, при этом процесс в памяти 200 Мб, способ "==" выполнен за 0.82 мсек, а способ "StringCompare" - 0.61 мсек.
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
AZJIO
beliy
Спасибо за помощь.
У меня на компьютере установлено AutoIt 3.6.1 от AZJIO . А новую справку, откуда мне скачать?
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
StarEdik
http://autoit-script.ru/index.php/topic,10070.new.html#new


Добавлено:
Сообщение автоматически объединено:

StarEdik
Обновил скрипт, забыл вписать маску, добавил исключение из списка самого файла, который передан для поиска и сделал вывод для теста. Для теста всместо 125 впиши 0, тогда ищет только в корне, это быстрее, скомпилируй и создай компии в корнях дисков. Проверено, работает.
 
Верх