Что нового

_FileDirList - Поиск файлов с использованием команды DIR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 552
Репутация
2 429
Вот решил выложить отдельно.
Позволяет искать файлы по нескольким маскам, с возможностью сортировки результата:

Код:
; #FUNCTION# ====================================================================================================
; Name...........:	_FileDirList
; Description....:	Search files and\or folders in a specified path (uses system Dir command)
; Syntax.........:	_FileDirList($sPath [, $sFileMask = "*" [, $iFlag = 0 [, $iSubDir = 1 [, $iSort = 0]]]])
; Parameters.....:	$sPath     - Path to search the file.
;					$sFileMask - [Optional] Filter to use, default is "*". Search the Autoit3 helpfile for the word "WildCards" For details.
;					$iFlag     - [Optional] Specifies whether to return files folders or both:
;                                                                                               $iFlag = 0 - Files and folders (default)
;                                                                                               $iFlag = 1 - Only files
;                                                                                               $iFlag = 2 - Only folders
;					$iSubDir   - [Optional] Specifies whether to search in subfolders or not:
;                                                                                               $iSubDir = 1 - Search in subfolders (default). Returns full pathes.
;                                                                                               $iSubDir = 0 - Search without subfolders (only in $sPath). Returns filenames only.
;					$iSort     - [Optional] Specifies whether to sort the output list (in alphabetic order) or not (default is 0 - do not sort).
;					
; Return values..:	Success    - An array with the following elements:
;                                                                      $aArray[0] = Number of Files\Folders returned
;                                                                      $aArray[1] = 1st File\Folder
;                                                                      $aArray[2] = 2nd File\Folder
;                                                                      $aArray[3] = 3rd File\Folder
;                                                                      $aArray[n] = nth File\Folder
;					Failure    - 0
;                      @Error:    1 = Path not found or invalid
;                                 2 = No File(s) Found
;
; Author.........:	G.Sandler (CreatoR), amel27.
; Modified.......:	
; Remarks........:	This function uses system Dir command, to speed up the search.
; Related........:	
; Link...........:	
; Example........:	
; ===============================================================================================================
Func _FileDirList($sPath, $sFileMask = "*", $iFlag = 0, $iSubDir = 1, $iSort = 0)
	Local $sOutBin, $sOut, $aOut, $aMasks, $sRead, $hDir, $sAttrib, $sFiles
	
	If Not StringInStr(FileGetAttrib($sPath), "D") Then
		Return SetError(1, 0, 0)
	EndIf
	
	If $iSubDir = 1 Then
		$sAttrib &= ' /S'
	EndIf
	
	If $iSort = 1 Then
		$sAttrib &= ' /O:N'
	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, '\\+$', '')
	$sFileMask = StringRegExpReplace($sFileMask, '^;+|;+$', '')
	$sFileMask = StringRegExpReplace($sFileMask, ';{2,}', ';')
	$aMasks = StringSplit($sFileMask, ';')
	
	For $i = 1 To $aMasks[0]
		If StringStripWS($aMasks[$i], 8) = "" Then
			ContinueLoop
		EndIf
		
		$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 ProcessExists($hDir)
		$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(2, 0, 0)
	EndIf
	
	$aOut[0] = UBound($aOut)-1
	Return $aOut
EndFunc


И пример:

Код:
#include <Array.au3>

$iTimer = TimerInit()
$aReturn = _FileDirList(@DesktopDir, "*.au3;*.txt")
ConsoleWrite(TimerDiff($iTimer) & @LF)

_ArrayDisplay($aReturn)
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 320
CreatoR,
Может имеет смысл еще добавить проверку на папку?
Код:
;...
If Not StringInStr(FileGetAttrib($sPath), 'D') Then
	Return SetError(1, 0, 0)
EndIf
;...
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 320
CreatoR,
Вы не объявили в локальных переменных $aMasks и вылазит ошибка, если использовать
Код:
Opt('MustDeclareVars', 1)
 

AZJIO

Меценат
Меценат
Сообщения
2 752
Репутация
1 149
Обнаружил интересное поведение...
Уже известно, что при маске *.xls в результат попадает *.xlsx и другие *.xls*
Если указать имя файла, например "*пример*.xls", то файлы подпадающие под маску "*пример*.xlsx" уже не будут найдены.
 

bic

Знающий
Сообщения
46
Репутация
14
Зависает функция.

Код:
#include <_FileDirList.au3>
Opt("TrayIconDebug", 1) ;0=не показать отладку, 1=показать отладку

$i = 0

While 1
	_FileDirList('C:\PerfLogs\')
	$i += 1
	ConsoleWrite($i & @CRLF)
	Sleep(100)
WEnd


TrayIconDebug показывает, что зависание происходит на 78-й строке.
Причем зависает так, что из скрипта, который использовал эту функцию, выйти нельзя, только убить процесс. Зависает всегда через разное время.
Методом научного тыка исправил эту проблему, поставив в цикл задержку в 10 мс. По многочисленным тестам, работает исправно

Код:
While 1
        $sRead = StdoutRead($hDir, False, True)

        If @error Then
            ExitLoop
        EndIf

        If $sRead <> "" Then
            $sOut &= $sRead
        EndIf

		Sleep(10)
    Wend
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 552
Репутация
2 429

bic

Знающий
Сообщения
46
Репутация
14
Функция намертво зависает. Целевая директория может быть пустой. Это не имеет значения.
А по другому исправить эту ошибку я не знаю как.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 552
Репутация
2 429
bic [?]
Функция намертво зависает. Целевая директория может быть пустой. Это не имеет значения.
А что ты этим примером пытаешься добиться?
 

bic

Знающий
Сообщения
46
Репутация
14
Пример - мониторинг директории через определенное время. А в консоли видно, что скрипт завис. Причем ни интервал, ни наличие файлов роли не играют.
Я просто подсказал решение от зависания функции. Может кому пригодится.
Или ты считаешь такое поведение функции нормальным?
 

joiner

Модератор
Локальный модератор
Сообщения
3 372
Репутация
589
проверил, не заметил зависания. цикл отрабатывается полностью без спотык. особенно на пустой папке :smile:
в основном процессор напрягается cmd.exe. можно заметить в диспетчере задач. и предлагаемая пауза не снижает потребляемости ресурсов. но любой поиск тянет на себя ресурс..в любой программе. хочешь быстрее значит жди. хочешь без напряга на систему, то будет в несколько раз дольше искать
в твоем случае основной напряг вызывает основной цикл, в котором ты запустил поиск
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 552
Репутация
2 429
bic [?]
Пример - мониторинг директории через определенное время.
Плохой пример.
Для этого есть другие методы.

в консоли видно, что скрипт завис
Проблема скорее всего в процессе cmd...

Я просто подсказал решение от зависания функции
Лучше заменить While 1 на While ProcessExists($hDir).
 

AZJIO

Меценат
Меценат
Сообщения
2 752
Репутация
1 149
Сейчас проверил аналогичную функцию от KaFu с маской
Код:
(@WindowsDir, "s*.???.*")

выдало 1631 результат, проверил _FileDirList, результат такой же. Остаётся непонятным вопрос, в маске находятся две точки, а результат содержит некоторые элементы совсем без точек.
 

C2H5OH

AutoIT Гуру
Сообщения
1 473
Репутация
333
Остаётся непонятным вопрос, в маске находятся две точки, а результат содержит некоторые элементы совсем без точек.
Как бы... http://autoit-script.ru/index.php/topic,4901.0.html
"." - соответствует любому одиночному символу, кроме символа новой строки
 

AZJIO

Меценат
Меценат
Сообщения
2 752
Репутация
1 149
C2H5OH
Не хочу хвастаться, но эта справка была написана после того, как я написал свою справку в RegExp, которую вы видите в официальной русской справке. Ну и второе, маска в _FileDirList не является регулярным выражением, в курсе что такое wildcards? Думаю по этому правилу в файле не может быть 2 расширения, то бишь две точки, отсюда вытекает что вторая точка либо игнорируется либо ищет по двум маскам (не тестил).
 

C2H5OH

AutoIT Гуру
Сообщения
1 473
Репутация
333
AZJIO,
да, я уже понял что речь не о регулярных выражениях.
Но у меня тут такие фокус команда DIR показывает...
Ща потестю немного, напишу.


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

Вот так хитро работает DIR

DOS
[box title=DOS] Volume in drive C has no label
Volume Serial Number is
Directory of C:\DOCS\DDD

213276~1 LIT 56 25.06.12 15:06
213289~1 DAT 27 25.06.12 17:23
213289~1 LIT 56 25.06.12 15:06
213328~1 DAT 27 25.06.12 17:23
213328~1 LIT 56 25.06.12 15:06
213666~1 LIT 56 25.06.12 15:06
213675~1 DAT 27 25.06.12 17:23
213675~1 LIT 56 25.06.12 15:06
213676~1 LIT 56 25.06.12 15:06
213700~1 DAT 27 25.06.12 17:23
213700~1 LIT 56 25.06.12 15:06
213829~1 DAT 27 25.06.12 17:23
213829~1 LIT 56 25.06.12 15:06
213829~2 DAT 27 25.06.12 17:23
213829~2 LIT 56 06.03.12 16:43
213829~3 DAT 27 25.06.12 17:23
213829~3 LIT 56 25.06.12 15:06
213829~4 LIT 56 25.06.12 15:06
213830~1 DAT 27 25.06.12 17:23
213830~1 LIT 56 25.06.12 15:06
213A66~1 LIT 56 25.06.12 15:06
213A76~1 LIT 56 25.06.12 15:06
213C72~1 LIT 56 25.06.12 15:06
213E66~1 LIT 56 25.06.12 15:06
24 file(s) 1112 bytes
1023932928 bytes free[/box]

XP
[box title=XP] Том в устройстве C не имеет метки.
Серийный номер тома:

Содержимое папки C:\DOCs\ddd

25.06.2012 15:06 56 212663303.lit
25.06.2012 17:22 27 213289791.dat
25.06.2012 15:06 56 213289791.lit
25.06.2012 17:22 27 213328710.dat
25.06.2012 15:06 56 213328710.lit
25.06.2012 15:06 56 212663300.lit
25.06.2012 17:22 27 213675926.dat
25.06.2012 15:06 56 213675926.lit
25.06.2012 15:06 56 212663304.lit
25.06.2012 17:22 27 213700639.dat
25.06.2012 15:06 56 213700639.lit
25.06.2012 17:22 27 213829790.dat
25.06.2012 15:06 56 213829790.lit
06.03.2012 16:43 56 213829792.lit
25.06.2012 17:22 27 213829795.dat
25.06.2012 15:06 56 213829795.lit
25.06.2012 17:22 27 213829796.dat
25.06.2012 15:06 56 213829796.lit
25.06.2012 17:22 27 213830738.dat
25.06.2012 15:06 56 213830738.lit
25.06.2012 15:06 56 212663301.lit
25.06.2012 15:06 56 212663305.lit
25.06.2012 15:06 56 212661236.lit
25.06.2012 15:06 56 212663302.lit
24 файлов 1 112 байт
0 папок 27 871 862 784 байт свободно[/box]

Под ХР DIR 213*.* даёт в списке файлы, которые начинаются на 212. Та же самая команда в DOS в том же каталоге, даёт фантастический результат, который объясняет почему эти файлы показываются по такому шаблону. Но почему происходит такая конвертация - загадка. Файлы реально называются так как показано в ХР-шном списке.
Может и с точками похожая ерунда?
 

Ромка Пупков

Новичок
Сообщения
25
Репутация
1
используя Вашу функцию в коде, требуется использовать конструкцию

Код:
$_eng = _FileDirList(@ScriptDir, '*conflicted copy*', 1)
For $i = 1 To $_eng[0]
	FileDelete($_eng[$i])
Next


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

Код:
"P:\DropboxPortableAHK\Dropbox\ChromePortable\test.au3" (6) : ==> Subscript used on non-accessible variable.:
For $i = 1 To $_eng[0]
For $i = 1 To $_eng^ ERROR
->15:21:21 AutoIt3.exe ended.rc:1
и код дальше не выполняется. проблема решилась комментированием строк

Код:
If @error Or UBound($aOut) < 2 Then
        Return SetError(2, 0, 0)
EndIf
мне кажется, нужно изменить их
 

erlik

Продвинутый
Сообщения
317
Репутация
84
Используйте _RecFileListToArray.
Для сравнения:
Код:
_FileDirList:             30 тыс файлов - 14985 мск
_RecFileListToArray: 30 тыс файлов - 2352 мск.

_FileDirList:             100 тыс файлов - 30406 мск
_RecFileListToArray: 100 тыс файлов - 8352 мск.
Вывод вполне очевиден - лично я давно променял первую на вторую.
 
Верх