Что нового

[Файловая система] Одновременный поиск файлов по двум маскам

A

at

Гость
День добрый, Сообщество. Прошу подсказать, как организовать поиск файлов server.txt и user.config в этом скрипте.

Код:
#Include <File.au3>

Global $4to = '10.10.1.20' ;Что менять
Global $na4to = '10.10.1.30' ;На что менять

_FindFiles('C:', 'server.txt')

Func _FindFiles($sRoot, $sFile)

    Local $FileList

    $FileList = _FileListToArray($sRoot, $sFile, 1)
    If Not @error Then
        For $i = 1 To $FileList[0]
            ConsoleWrite($sRoot & '\' & $FileList[$i] & @CR)
            $Read = FileRead($sRoot & '\' & $FileList[$i]) ;Считываем
            $Open = FileOpen($sRoot & '\' & $FileList[$i], 2) ;Открываем
            $Replace = StringRegExpReplace($Read, $4to, $na4to) ;Изменяем
            FileWrite($Open, $Replace) ;Переписываем
            FileClose($Open) ;Закрываем
        Next
    EndIf
    $FileList = _FileListToArray($sRoot, '*', 2)
    If Not @error Then
        For $i = 1 To $FileList[0]
            _FindFiles($sRoot & '\' & $FileList[$i], $sFile)
        Next
    EndIf
EndFunc
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
at,
Попробуйте так.
Код:
;#include <Array.au3>

$sFirstSearchFile = 'server.txt'
$sSecondSearchFile = 'user.config'
$sWhereSearch = @HomeDrive
$aSearch = _FileSearch($sWhereSearch, $sFirstSearchFile & ';' & $sSecondSearchFile, 1)
If @error Then
	MsgBox(16, 'Error', '_FileSearch')
	Exit
EndIf
If Not $aSearch[0] Then
	MsgBox(16, 'Error', 'Not files')
	Exit
EndIf
;_ArrayDisplay($aSearch)
For $i = 1 To $aSearch[0]
	;Делайте с найденными файлами то, что Вам надо
	;для примера
	ConsoleWrite($aSearch[$i] & @TAB & FileGetSize($aSearch[$i]) & ' b' & @LF)
Next

;CreatoR; http://autoit-script.ru/index.php?topic=315.msg18672#msg18672
Func _FileSearch($s_Path_Search, $s_File_Mask = '*', $i_Flag = 0, $i_SubDir = 1)
	;фильтры для поиска нужно указывать через ";"
	;$i_Flag = 0 - Файлы и папки (по умолчанию)
	;$i_Flag = 1 - Только файлы
	;$i_Flag = 2 - Только папки (если ищем конкретную папку, то надо добавлять к имени * в начало  или в конец)
	;$i_SubDir = 1 - Искать во всех подкаталогах (по умолчанию). Возвращает полные пути.
	;$i_SubDir = 0 - Искать только в самой папке. Возвращает только имена файлов(папок).
	Local $s_Out, $a_Out, $s_Read, $h_Dir, $s_Attrib, $s_Subdir, $a_Masks

	If StringRight($s_Path_Search, 1) == '\' Then ;нужно, если $s_Path_Search - диск (например C:\)
		$s_Path_Search = StringTrimRight($s_Path_Search, 1)
	EndIf
	If $i_SubDir Then
		$s_Subdir = ' /S /B'
	Else
		$s_Subdir = ' /B'
	EndIf
	Switch $i_Flag
		Case 1
			$s_Attrib = ' /A-D'
		Case 2
			$s_Attrib = ' /AD'
		Case Else
			$s_Attrib = ' /A'
	EndSwitch
	$s_Out = StringToBinary('0' & @CRLF, 2)
	$a_Masks = StringSplit($s_File_Mask, ';')
	For $i = 1 To $a_Masks[0]
		$h_Dir = Run(@ComSpec & ' /U /C DIR "' & $s_Path_Search & '\' & $a_Masks[$i] & '"' & $s_Subdir & $s_Attrib, @SystemDir, @SW_HIDE, 6)
		If Not $h_Dir Then Return SetError(1)
		While 1
			$s_Read = StdoutRead($h_Dir, False, True)
			If @error Then
				ExitLoop
			EndIf
			If $s_Read Then
				$s_Out &= $s_Read
			EndIf
			Sleep(10)
		WEnd
	Next
	$a_Out = StringRegExp(BinaryToString($s_Out, 2), '[^\r\n]+', 3)
	If @error Then Return SetError(1)
	$a_Out[0] = UBound($a_Out) - 1
	Return $a_Out
EndFunc   ;==>_FileSearch
 
Автор
A

at

Гость
madmasles, а могу я сразу объединить эти файлы одной переменной?
Код:
$sFirstSearchFile = 'server.txt'
$sSecondSearchFile = 'user.config'
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
at [?]
а могу я сразу объединить эти файлы одной переменной?
Код:
;...
$sSearchFiles = 'server.txt;user.config';можно еще файлы добавлять через ";"
$sWhereSearch = @HomeDrive
$aSearch = _FileSearch($sWhereSearch, $sSearchFiles, 1)
;...
Или так:
Код:
;...
$aSearch = _FileSearch(@HomeDrive, 'server.txt;user.config', 1)
;...
Или так:
Код:
;...
$aSearch = _FileSearch('C:', 'server.txt;user.config', 1)
;...
 
Автор
A

at

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

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
at
Можешь ещё попробовать эту _FileSearch, в полтора раза быстрей работает.

Код:
#include <Array.au3> ; для _ArrayDisplay
#include <_FileSearch.au3>

$sFirstSearchFile = 'server.txt'
$sSecondSearchFile = 'user.config'
$sWhereSearch = @HomeDrive

$timer = TimerInit()
$aSearch = _FileSearch($sWhereSearch, $sFirstSearchFile & '|' & $sSecondSearchFile)
$timer = Round(TimerDiff($timer) / 1000, 2) & ' сек'
_ArrayDisplay($aSearch, $timer&' - время')
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
at,
Я немного исправил функцию, теперь, если ищем больше одного файла, у меня отрабатывает гораздо быстрее.
Код:
#include <Array.au3>

$iStart = TimerInit()
$aReturn = _FileSearch(@HomeDrive, '*.au3|*.txt', 1)
$sTime = StringFormat('%.2f sec', TimerDiff($iStart) / 1000)
_ArrayDisplay($aReturn, $sTime)

;CreatoR; http://autoit-script.ru/index.php?topic=315.msg18672#msg18672
Func _FileSearch($s_Path_Search, $s_File_Mask = '*', $i_Flag = 0, $i_SubDir = 1)
	;!!! фильтры для поиска нужно указывать через "|" !!!
	;$i_Flag = 0 - Файлы и папки (по умолчанию)
	;$i_Flag = 1 - Только файлы
	;$i_Flag = 2 - Только папки (если ищем конкретную папку, то надо добавлять к имени * в начало  или в конец)
	;$i_SubDir = 1 - Искать во всех подкаталогах (по умолчанию). Возвращает полные пути.
	;$i_SubDir = 0 - Искать только в самой папке. Возвращает только имена файлов(папок).
	Local $s_Out, $a_Out, $s_Read, $h_Dir, $s_Attrib, $s_Subdir, $s_Parameter, $a_Masks

	If StringRight($s_Path_Search, 1) == '\' Then ;нужно, если $s_Path_Search - диск (например C:\)
		$s_Path_Search = StringTrimRight($s_Path_Search, 1)
	EndIf
	$a_Masks = StringSplit($s_File_Mask, '|')
	For $i = 1 To $a_Masks[0]
		$s_Parameter &= '"' & $s_Path_Search & '\' & $a_Masks[$i] & '";'
	Next
	$s_Parameter = StringTrimRight($s_Parameter, 1)
	If $i_SubDir Then
		$s_Subdir = ' /S /B'
	Else
		$s_Subdir = ' /B'
	EndIf
	Switch $i_Flag
		Case 1
			$s_Attrib = ' /A-D'
		Case 2
			$s_Attrib = ' /AD'
		Case Else
			$s_Attrib = ' /A'
	EndSwitch
	$s_Parameter &= $s_Subdir & $s_Attrib
	$s_Out = StringToBinary('0' & @CRLF, 2)
	$h_Dir = Run(@ComSpec & ' /U /C DIR ' & $s_Parameter, @SystemDir, @SW_HIDE, 6)
	If Not $h_Dir Then Return SetError(1)
	While 1
		$s_Read = StdoutRead($h_Dir, False, True)
		If @error Then
			ExitLoop
		EndIf
		If $s_Read Then
			$s_Out &= $s_Read
		EndIf
		Sleep(10)
	WEnd
	$a_Out = StringRegExp(BinaryToString($s_Out, 2), '[^\r\n]+', 3)
	If @error Then Return SetError(1)
	$a_Out[0] = UBound($a_Out) - 1
	Return $a_Out
EndFunc   ;==>_FileSearch
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
madmasles
Мой вариант пока рекорд держит :smile:
_RecFileListToArray проигрывает за счёт использования регулярного выражения для каждого найденного файла индивидуально.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
AZJIO [?]
Мой вариант пока рекорд держит
Проверил, у меня через ком. строку (последний вариант) работает быстрее. Проверял на старом и слабом ноутбуке (Win XP, ~14000 файлов) и на нормальном ноутбуке (Win 7, ~5000 файлов). Перед каждой проверкой перезагружался и запускал поиск через одну минуту. Искал по маске:
Код:
;...
$aReturn = _FileSearch('C:', '*.au3|*.txt|*.ini', 1)
;...

У меня следующие результаты:
AZJIO
Win XP 3.3.6.1: 101.54 sec
Win XP 3.3.8.0: 111.63 sec
Win 7 3.3.6.1: 48.28 sec
Ком. строка
Win XP 3.3.6.1: 97.18 sec
Win XP 3.3.8.0: 103.52 sec
Win 7 3.3.6.1: 37.49 sec
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
madmasles [?]
Я немного исправил функцию, теперь, если ищем больше одного файла, у меня отрабатывает гораздо быстрее
Что конкретно изменилось?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
CreatoR [?]
Что конкретно изменилось?
В Вашем варианте, при поиске нескольких масок, команда DIR выполняется в цикле по очереди для каждой маски. Я почитал справку к команде DIR и обнаружил, что:
Примечания
Использование нескольких имен_файлов Допускается использование нескольких имен_файлов. Разделяйте имена файлов пробелом, запятой или точкой с запятой. Для вывода группы файлов допускается применение подстановочных знаков (? и *) в параметре имя_файла.
Именно это я и сделал.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
madmasles [?]
Именно это я и сделал
Спасибо.

Тогда я бы уже сделал так (покомпактнее):

Код:
Func _FileSearch($sPath, $sFileMask, $iFlag = 0, $iSubDir = 1)
	Local $sOutBin, $sOut, $aOut, $sRead, $hDir, $sAttrib, $sFiles
	
	If $iSubDir = 1 Then
		$sAttrib = ' /S'
	EndIf
	
	Switch $iFlag
		Case 1
			$sAttrib &= ' /A-D'
		Case 2 
			$sAttrib &= ' /AD'
		Case Else 
			$sAttrib &= ' /A'
	EndSwitch
	
	$sOut = StringToBinary('0' & @CRLF, 2)
	$sPath = StringRegExpReplace($sPath, '\\+$', '')
	$aMasks = StringSplit($sFileMask, ';')
	
	For $i = 1 To $aMasks[0]
		$sFiles &= '"' & $sPath & '\' & $aMasks[$i] & '"'
		
		If $i < $aMasks[0] Then
			$sFiles &= ';'
		EndIf
	Next
	
	$hDir = Run(@ComSpec & ' /U /C DIR ' & $sFiles & ' /B' & $sAttrib, @SystemDir, @SW_HIDE, 6)
	
	While 1
		$sRead = StdoutRead($hDir, False, True)
		
		If @error Then
			ExitLoop
		EndIf
		
		If $sRead <> "" Then
			$sOut &= $sRead
		EndIf
	Wend
	
	$aOut = StringRegExp(BinaryToString($sOut, 2), '[^\r\n]+', 3)
	
	If @error Or UBound($aOut) < 2 Then
		Return SetError(1)
	EndIf
	
	$aOut[0] = UBound($aOut)-1
	Return $aOut
EndFunc
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
CreatoR,
А не лучше тогда так?
Код:
;...
$aOut = StringRegExp(BinaryToString($sOut, 2), '[^\r\n]+', 3)
If @error Then Return SetError(1)
If UBound($aOut) < 2 Then Return SetError(2);т.е. нет файлов.
;...
Хотя... Я старый Ваш вариант использую давно и часто, и привык, если нулевой элемент равен 0, то файл(ы) не найден(ы).
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gregaz [?]
При повторном поиске без перезагрузки скорсть ведь будет раз в 15 быстрее
Это я знаю. Я же сравнивал скорость двух вариантов поиска и перезагружался, чтобы оба проверяемых варианта были в равных условиях.
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
А что разве другие варианты тоже будут быстрее ?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gregaz [?]
А что разве другие варианты тоже будут быстрее ?
У меня да, так же, как и с командной строкой.
Мне непонятно другое, вариант с командной строкой находит у меня на 3 файла больше, почему?
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
А за счет чего происходит увеличение скорости ?
Предполагаю ,что при первичном поиске инфа куда-то заносится и
при повторном поиске используется. Если да, то куда заносится ?
Есть ли возможность определить выполнялся ли первичный поиск.

Я почему спрашиваю. Давно пользуюсь поиском вариантом от Creatora.

И обратил внимание, что где-то в течение суток можно осуществлять быстрый поиск(если конечно не перезагружаться)
На следующий день придется долго ждать (1 Раз)
 
Верх