Что нового

FileFindXXX

SyDr

Сидра
Сообщения
651
Репутация
158
Написал себе функцию для поиска всех файлов и папок в заданной папке.
Оказалось, что для пустых папок мой пример не работает.
Проверка показала, что это происходит из-за того, что значение @error после выполения функции FileFindNextFile равняется 0 :shok: Из-за этого я не могу определить, что искать в этой папке ничего не надо.

Код:
Global $A[1]
#include
Global $I = 0
F($A, $I, "D:\Downloads\Text", "D:\Downloads\Text")
_ArrayDisplay($A)
Func F(ByRef $A, ByRef $I, $PD, $SD)
	FileChangeDir($SD)
	ReDim $A[2 * $I + 1]
	Local $H = FileFindFirstFile("*.*")
	While 1
		$A[$I] = @WorkingDir & "\" & FileFindNextFile($H)
;~ SleeP(100)
		If @error And FileClose($H) Then ExitLoop
;~ ConsoleWrite(@error & @CRLF)
		$I += 1
		If $I >= UBound($A) - 1 Then ReDim $A[2 * $I]
		If FileExists($A[$I - 1] & "\") Then F($A, $I, @WorkingDir, $A[$I - 1])
	WEnd
	FileChangeDir($PD)
	If $PD = $SD Then ReDim $A[$I + 1]
EndFunc


Помогите, может это я где ошибся. Назначение параметров функции:
1 - массив, в котором будут висеть результаты.
2 - чтобы знать, с каким элементов массива работать. В начале равно 0
3, 4 - папка для поиска. При вызове извне - должны совпадать, иначе результат я предсказать не могу.

P. S. Не смотрите на мою проверку, является ли найденное папкой. Я забыл, что в этом случае функция устанавливает @extended.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Re: FileFindNextFile и пустые папки.

Ну во-первых хочу заметить, что это извращённый метод кодинга ;D Код доолжен быть максимально понятен не только скриптеру, но и другим.

SyDr « Создано: Сегодня в 22:36:22 »
не могу определить, что искать в этой папке ничего не надо
Вообще-то нужно проверять $H, вернул ли он указатель или -1.
А ещё проврка на “пустотность” папки делается так:

Код:
;Переменной $IsEmpty присваивается значение возвращаемое ф-ей _DirIsEmpty()
$IsEmpty = _DirIsEmpty("c:\Temp")

;Отображение содержимого переменной $IsEmpty и уровень ошибочности
MsgBox(64, "Results", "$IsEmpty = " & $IsEmpty & @LF & "@error = " & @error)

;Функция проверяет если каталог по заданному пути не содержит файлы/папки.
;Если папка не существует (по пути из переменной $sPath), то @error = 1 и возвращается 0
;Если папка существует, и она *не* пуста, то возвращается 0
;Если папка существует, и она *пуста*, то возвращается 1
Func _DirIsEmpty($sPath)
	;Если атрибут папки не содержит D (от слова Dir), то устанавливаем уровень ошибочности и возвращаем 0
	If Not StringInStr(FileGetAttrib($sPath), "D") Then Return SetError(1, 0, 0)
	
	;Инициализация поиска *любого* файла в указанном пути
	Local $hSearch = FileFindFirstFile($sPath & "\*")
	
	;"Запоминаем" уровень ошибочности
	Local $iRet = @error
	
	;Закрытие хендла (управляющего) после инициализации поиска (обязательно)
	FileClose($hSearch)
	
	;Возвращаем уровень ошибочности ($iRet),
	;FileFindFirstFile() возвращает @error = 1 если папка пуста, это и есть индикация того, что она пуста :)
	Return $iRet
EndFunc


Я забыл, что в этом случае функция устанавливает @extended.
Лучше проверять по StringInStr(FileGetAttrib(...), "D"), @extended пока не надёжная, об этом есть баг-репорты.
 
Автор
SyDr

SyDr

Сидра
Сообщения
651
Репутация
158
Re: FileFindNextFile и пустые папки.

CreatoR
CreatoR сказал(а):
Ну во-первых хочу заметить, что это извращённый метод кодинга ;D Код доолжен быть максимально понятен не только скриптеру, но и другим.
Каюсь, грешен :-[ Или это компилимент? ;D Дело в том, что писал я это не за компьютером, а на листике.

Вообще-то нужно проверять $H, вернул ли он указатель или -1.
Вот здесь я и попался.

CreatoR сказал(а):
Лучше проверять по StringInStr(FileGetAttrib(...), "D")
Эм... А мой вариант нормальный? Ведь если $Patth & "\" существует - то это не файл. Я могу ещё shell.application использовать. Всё равно он по полной программе будет использоваться.

Конечный вариант:
Код:
#include <Array.au3>

Global $A[1]
Global $I = 0
_FileListR($A, $I, "D:\Music")
_ArrayDisplay($A)


Func _FileListR(ByRef $rArray, ByRef $cNumber, $ParentDir, $SearchDir = $ParentDir)
	FileChangeDir($SearchDir) ; Переходим в каталог для поиска
	ReDim $rArray[2*$cNumber+1] ; Изменяем раземр массива. Когда $cNumber равно 0 - размер массива равен 1
	Local $sHandle = FileFindFirstFile("*") ; Инициализируем поиск
	While 1
		If @error And FileClose($sHandle) Then ExitLoop ; Если каталог пуст - закрываем хэндл и прекращаем поиск
		$rArray[$cNumber] = @WorkingDir & "\" & FileFindNextFile($sHandle) ; Иначе заносим в массив полный путь к найденному элементу
		If @error And FileClose($sHandle) Then ExitLoop ; Если файлы/каталоги закончились - закрываеи хэндл и прекращаем поиск
		$cNumber += 1 ; Иначе переходм к следующему элементу массива
		If $cNumber >= UBound($rArray) Then ReDim $rArray[2*$cNumber] ; Если место в массиве закончилось - удваиваем его размер
		If FileExists($rArray[$cNumber-1] & "\") Then _FileListR($rArray, $cNumber, @WorkingDir, $A[$cNumber-1]) ; Если найденное - каталог, то продолжаем поиск в нём.
	WEnd
	FileChangeDir($ParentDir) ; Переходим в родительский каталог
	If $ParentDir = $SearchDir Then ReDim $rArray[$I] ; Если родительский каталог = каталог для поиска (поиск закончен) - уменьшаем размер массива до необходимого
EndFunc
 
Автор
SyDr

SyDr

Сидра
Сообщения
651
Репутация
158
Re: FileFindNextFile и пустые папки.

SyDr сказал(а):
Эм... А мой вариант нормальный? Ведь если $Patth & "\" существует - то это не файл.
Упс... Мой вариант работает в 5 раз медленнее.. :smile:

Исправил своё чудо ещё раз. Скорость работы увеличена в 10 раз ;D Вот что значит убрать лишнее :smile:

Текущая скорость обработки - ~3000 файлов/сек.
Код:
#include <Array.au3>

Global $A[1]
Global $I = 0
_FileListR($A, $I, "D:\Music")
_ArrayDisplay($A)


Func _FileListR(ByRef $rArray, ByRef $cNumber, $ParentDir, $SearchDir = $ParentDir)
	FileChangeDir($SearchDir) ; Переходим в каталог для поиска
	Local $sHandle = FileFindFirstFile("*") ; Инициализируем поиск
	While 1
		If $sHandle = -1 Then ; Если каталог пуст изначально - закрываем хэндл и прекращаем поиск
			FileClose($sHandle)
			ExitLoop
		EndIf
		$rArray[$cNumber] = @WorkingDir & "\" & FileFindNextFile($sHandle) ; Иначе заносим в массив полный путь к найденному элементу
		If @error Then ; Если файлы/каталоги закончились - закрываеи хэндл и прекращаем поиск
			FileClose($sHandle)
			ExitLoop
		EndIf
		$cNumber += 1 ; Иначе переходм к следующему элементу массива
		If $cNumber >= UBound($rArray) Then ReDim $rArray[2*$cNumber] ; Если место в массиве закончилось - удваиваем его размер
		If StringInStr(FileGetAttrib($rArray[$cNumber-1]), "D") Then _FileListR($rArray, $cNumber, @WorkingDir, $A[$cNumber-1]) ; Если найденное - каталог, то продолжаем поиск в нём.
	WEnd
	FileChangeDir($ParentDir) ; Переходим в родительский каталог
	If $ParentDir = $SearchDir Then ReDim $rArray[$I] ; Если родительский каталог = каталог для поиска (поиск закончен) - уменьшаем размер массива до необходимого
EndFunc
 
Верх