Что нового

FileOperations - Файловые операции (поиск файлов и др.)

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
AutoIt: 3.3.6.1 - 3.3.8.1
Версия: 1.8.2

Категория: Файловая система

Описание:
_FO_FileSearch - функция поиска файлов
_FO_FolderSearch - функция поиска папок
_FO_CorrectMask - функция корректирующая маску
_FO_SearchEmptyFolders - функция поиска пустых папок
_FO_FileDirReName - функция переименования файла
_FO_GetCopyName - функция вычисления нового имени копии файла, несуществующего
_FO_FileBackup - функция создаёт резервную копию файла
_FO_PathSplit - функция делит путь на 3 части в массив
_FO_IsDir - функция проверяет, является ли объект каталогом (можно использовать и для проверки что файл).
_FO_IsEmptyFolder - функция проверяет, является ли папка пуста
_FO_ShortFileSize - функция преобразует байты в число, до 3 значащих цифр с приставкой

Файл: FileOperations.7z (Содержит UDF, примеры, справку)

История версий:
2013.09.04
Улучшение регулярных выражений, оптимизации

2013.08.02
Добавлено _FO_IsEmptyFolder
Удалена проблема с AU3Check

2013.06.15
Добавлено _FO_ShortFileSize
В функцию поиска файлов добавлены два параметра для исключения каталога из поиска
Улучшен параметр чуствительности к регистру, не требует указывать диапазон

2013.04.28
Поиск пустых папок теперь выдаёт ошибку при указании файла вместо папки

2013.04.27
Исправлено, если путь пустая строка, это не вызывало ошибки

2013.01.03
Удалены $i из объявления, так как они для цикла For принудительно локальные.
Tidy

2012.11.20
Добавлена функция _FO_IsDir
Добавлен CHM-файл с описанием

2012.08.08
Улучшен параметр учёта регистра
Текст локализации _FO_GetCopyName вынесен в опциональный передаваемый параметр

2012.06.09
Добавлена функция __FO_UserLocale, чтобы не учитывать регистр букв для локального языка.

2012.05.20
В функцию _FO_SearchEmptyFolders добавлен параметр $iFull - полный или относительный путь

2012.05.19
Добавлены две функции _FO_FileBackup, _FO_PathSplit

2012.05.14
Добавлены две функции _FO_FileDirReName и _FO_GetCopyName

2012.02.22
Улучшен Gui_Test_Search.au3 для с готовым выбором путей для тестирования
Использовавние ByRef увеличило скорость на 2.5%

2012.02.21
Присвоение символа "\" поставил до проверки пути, теперь путь к файлу не будет валидным

2012.02.16
Для избавления от возможных конфликтов аналогичных одноимённых функций других скриптёров AutoIt3, к функции добавлен префикс _FO
UDF названа FileOperations.au3
Добавлена функция _FO_SearchEmptyFolders - поиск пустых папок

2012.02.15
Убрал лишнюю объявленную переменную $i найденную с помощью Au3Check (не критично)
Для избавления проблем обфускации функция __MaskUnique добавлена в исключение директивами #Obfuscator_Off и #Obfuscator_On
Добавлены префиксы типов переменных

2012.01.10
Коррекция маски выведена в отдельную функцию _FO_CorrectMask
Добавлена проверка уникальности элементов маски

2011.11.27
Всвязи с тем что некоторые программы (в отличии от эксплорера) позволяют переименование файла с добавлением пробела или точки в начало имени, то функция не корректирует маску по этому критерию, то есть корректирует только в отношении окончания файла.
Исправлены некритические ошибки

2011.11.9
Символ разделителя ";" заменён на "|", по причине, что ";" может присутствовать в именах файлов, а значит в маске, что не должно препятствовать поиску. В случае конфликта с разделителем в скрипте можно использовать Opt("GUIDataSeparatorChar", Chr(1)) или использовать свой разделитель, а при передаче опций в функцию сделать замену разделителя в маске, например _FO_FileSearch($Path, StringReplace($Mask, ';', '|'))
Изменён порядок проверки валидности маски для наилучшего детектирования и/или исправления ошибок маски

2011.10.24
Исправлена ошибка при комбинайии Full=3 и Arr=1
Увеличена в 2 раза скорость работы _FO_FolderSearch

2011.10.22
Исправлен возврат функции __GetListMask

2011.10.17
Добавлен параметр $TypeMask с принудительной опцией маски

2011.10.15
Добавлен возврат ошибки @error = 3 - если не найдено файлов (кстати, спорный параметр, так как не найденность не является ошибкой а только отсутсвием результа, что является тоже результатом. В любом случае есть 2 варианта - программы, в которых отсутствие результата является ошибкой, так как нет смысла в дальнейшей обработке данных и программы, в которых отсутствие результата не вызывает проблем и затрат, обычное присоединение данных к предыдущему результату без обработки ошибок)

2011.10.14
Добавлен параметр $Include = True/False в функцию _FO_FolderSearch


2011.10.12
Исправление функции __FO_FileSearchMask

2011.10.10
Исправлено $Include=False, когда файлы без расширения не попадали в список исключений
Добавлена функция маски с обработкой регулярным выражением

Источник: autoitscript.com (параллельная тема)
Автор(ы): AZJIO
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Неплохая библиотека. Несколько раз пользовался. Особо нравится скорость работы и то что не загружает CPU.
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
Чтобы не обсуждать функцию в разделе справки продолжаю здесь дискуссию

joiner
Небольшой расклад:
1. Позиционирование моего варианта было по скорости, потому что я посчитал, что обработка списка за один проход будет быстрее чем вызов регулярного выражение на каждый файл. Обгон был в ~2 раза 0.43 мс против 0.75 мс для папки Windows, или 4 сек против 10 сек для диска C. Иногда оппоненты приводят заявления, что если уменьшить количество проверок, то это является причиной, по которой функция может работать быстрее, то есть смысл подан и многие начинают верить, хотя опять же говорится это в общем, то есть как бы и опровергать то нечего, но смысл как бы заложен. На самом деле выйгрышь только за счёт обработки регулярным выражением всего списка.

2. Функция от Melba23 добавлена в версию 3.3.9.19, а в ней регулярные выражения имеют уже новый движок, вренее тот же движок но с обновлённой версией и новыми параметрами компиляции движка PCRE, а именно: если раньше вызвать функцию регулярного выражения с пустыми параметрами в цикле, то скорость достаточно высока, то есть сам вызов не мог тормозить функцию, но тормозит её то, что якобы данные переданные для обработки и данные обрабатываемые внутри движка в разных форматах, поэтому приходится приводить к одному формату. На новом движке (с включенным флагом юникода при компиляции проекта) этой проблемы нет, а значит разрыв должен уменьшиться почти до нуля (я ещё не проверял). Во вторых добавленная в мою функуию полезный параметры "Не учитывать регистр букв для всех языков" тоже покрывается обновлённым движком, так как теперь он компилируется с поддержкой UTF16 внутри движка и теперь \w включает символы русские и вообще любые, арабские, турецкие и т.д., аналогично (?i) также не учитывает регистр и для кириллицы.

3. Многим нравится, что функция от Melba23 поддерживает сортировку, атрибуты, но я к примеру многие такие фичи считаю пустыми, так как я вполне могу отправить полученный результат в _ArraySort и будет такая же сортировка, также я могу прокрутить массив в параллельном цикле для получения атрибутов. То есть я не вижу причин, чтобы включать эти фичи в функцию дополнительным флагом, тем самым усложняя пользовательский интерфейс функции. Хотя прирост скорости всё же есть за счёт использования расширенного вызова API, которая сразу получает атрибуты и файл, то есть при указании атрибутов функция переключается на использование расширенного вызова, тем самым работает быстрее чем сумма функций получение файла и запроса атрибутов.
Кстати при запросе файлов у Melba23 используется алгоритм, который возвращает файлы в обратном порядке в пределах каждой папки и это требует обязательной сортировки, если необходимо сделать список для просмотра. Моя функция запрашивает упорядоченно, но это всё же не соответствует точной сортировке как в проводнике, так как FAT32 выдаёт полностью не сортированный порядок файлов, а NTFS выдаёт сортированный в пределах алфавита и цифр, но в остальных спец-символах сортировка не соответствует. В принципе результат получается достаточно сортированный и в 90% случаев не требует сортировки для представления результата списком. У Melba23 для представления сортировать нужно в любом случае. Но известно, что частично сортированный результат сортируется быстрее.

4. Флаг исключить маску немного удивлял тем, что мы указываем маску доступных, например "exe|dll" и указываем исключения, например jpg, но сама маска уже определяет что включать, а что будет исключено. Возможен конечно случай, когда создавая маску включения трудно описать исключения, но опять же я в реальной ситуации я не сталкивался с необходимостью, только мог выдумать причину, что это может когда то пригодиться.

5. Маска (у Melba23) использует разделитель ";", но этот символ может быть в имени файла, соответственно накладывает ограничение.

6. Многие параметры конфликтуют между собой, в зависимости ищем ли мы папку или файлы и в зависимости рекурсивный ли поиск, это немного путает, поэтому я и сделал раздельные функции для папки и файлов. Я не нахожу причин получать вместе папки и файлы для рекурсивного поиска, потому что не нахожу случаев, когда это можно обрабатывать вместе.

7. Кроме того проверку маски я вынес в отдельную функцию _FO_CorrectMask. Она не тратит слишком много времени, но разграничивает вариант, когда маска указывается внутри скрипта и программист не ошибается, так как тестирует и может применять в цикле функцию и вариант когда маска указывается пользователем и вероятность ошибки существует, то _FO_CorrectMask достаточно точно проверяет все ошибки и не пропустит неверную маску

Я добавил флаг исключения каталогов и то по причине просьбы, хотя в реальности сам я его ни разу не применял, кроме теста конечно же.
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
AZJIO [?]
На новом движке этой проблемы нет, а значит разрыв должен уменьшиться почти до нуля (я ещё не проверял)
я запускал обе функции на бета-версии AutoIT.
делал поиск на физическом диске, который содержит операционную систему . в итоге файлов - 187957
_FileListToArrayRec - без сортировки время поиска примерно 9906.6476637508
с сортировкой примерно 21084.295796885
функция _FO_FileSearch - время поиска 4666.9238318754
при написании своих кодов использовал _FO_FileSearch . делал разные тесты. ошибок не было.
в итоге решающее значение имеет скорость
я , конечно, далек от понимания всех тонкостей программирования и особенно регулярных выражений, но я смотрю на результат.
разница огромна и на бета-версии.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
AZJIO
Есть небольшой совет, библиотека написана отлично, но было бы еще лучше, правильнее что ли, если бы входные параметры проверялись на слово Default. Это очень удобно, потому что в таком случае не нужно смотреть в справку и подставлять вручную значения по умолчанию для каждого параметр, если мне нужно всего лишь поменять 3 параметр. Так я могу писать, default,default, 1 вместо -1,'|',1. И однажды написав так, можно смело обновляться до новейших версий библиотек, не задумываясь о том, поменял ли автор параметры по умолчанию.
Конечно это мое личное мнение, и вы можете писать так как вам удобнее, но мне кажется что это очень хорошая практика кода для библиотек.
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
joiner
Я предлагал Melba23 сделать итерационный вариант, но с другим алгоритмом, при котором результат будет более сортированным. Он чем то похож на рекурсивный вариант. То есть у Melba23 есть массив, который при нехватке увеличивается в два раза чтобы вместить следующую порцию файлов. И используется один дескриптор поиска. Я предложил создать массив в который возвращается открытые дескрипторы поиска, а результат отправлять в список. Смысл в том что глубина поиска не более 123 и поэтому размер массива заранее известен и равен 123. Хотя принцип удвоения массива не ресурсоёмкий, то есть требует ограниченное количество вызовов и не влияет на скорость, проблема только в принудительной десортировки результата. Если использовать мой итерационный вариант, то эта проблема решается.


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

inververs [?]
Об этом я спорил на офсайте. Когда добавляются такие проверки, то добавляется целый блок на 10 параметров. Хорошо если функция вызывается однократно, но если используется в цикле без рекурсии, когда отношение времени запроса к времени проверки входных параметров слишком мал, то это станет заметным. Реально такое изменение было принято только для функции _ArrayDisplay (3.3.9.19), так что политика и на офсайте использование ключевого слова default только в случае разового использования. И кроме того не понятно какие параметры используются по умолчанию, то есть я их смотрю в строке вызова или в строке функции, а как вам такой такая неинформативная строка:
Код:
Func _ArrayDisplay(Const ByRef $avArray, $sTitle = Default, $iItemLimit = Default, $iTranspose = Default, $sSeparator = Default, $sReplace = Default, $sHeader = Default)
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
AZJIO
Конечно, если это идет в ущер скорости, то лучше обойтись без этого.
А на счет
AZJIO [?]
какие параметры используются по умолчанию
ничто не мешает написать как обычно
Код:
Func _ArrayDisplay(Const ByRef $avArray, $sTitle = '', $iItemLimit = -1, $iTranspose = 0, $sSeparator = '', $sReplace = '|', $sHeader = '')
а уже внутри, проверять типа
Код:
If $sTitle = Default Then $sTitle=''
итд
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
joiner
Потому что я сохранил его идею проверку расширения для каждого файла в отдельности. Если эту идею нарушить то с ней будут недоступны расширенный вызов атрибутов (хотя я считаю что залог скорости такой, что позволит мне 2 раза проверить атрибуты). Я просто показал другой способ итерации, когда результат будет сортированным или точнее частично сортированным (на 90%).


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

inververs
У меня привычка, я копирую строку с параметрами по умолчанию, а потом изменяю если требуется указать иное. Если вы будете копировать указывать default, мне кажется вам всё равно будет интересно чем же является этот default, и также придётся следить за его позицией в списке параметров, в той ли позиции я поставил default. В общем я пока не разделяю этого. Если бы это было в Си и у нас компиляция бы оптимизировала код, но в AutoIt3 это ещё и много букв для интерпретатора.


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

joiner
Я там выложил 3 функции, 1-я рекурсивная, и 2 итерационных, то что в средине работает со списком и должна быть быстрая.
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
я тестировал два кода из 37 сообщения. оба дали одинаковые результаты по времени
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
joiner
Да одинаковый для обоих 0.51 и 0.53 против 0.43 _FO_FileSearch. Просто там используется флаг папки или файл и в первом результат лишний раз преобразуется в список. Ну это не оптимизированный вариант. Нужно определится с параметрами и из этого сделать оптимизацию под конкретный алгоритм. Я думаю функции файлов и папок должны быть раздельными, это уже сократит время. Ни кто идею не воспринял, а мне лишний раз вылизывать то что будет отвергнуто не интересно. Идея сделать итерационный вариант в принципе то же самое, и для меня не несёт каких то примуществ перед рукурсивным.
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
AZJIO
и все-таки раздельный вариант функций поиска файлов и папок будет более универсален, чем одна функция поиска и того и другого. хотя именно она может казаться универсальной, но окажется менее рациональной.
я про данный случай.
от меня - я благодарен тебе за твою UDF. считаю, что она не менее достойна для включения в официальный сборник UDF.
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
joiner
1. Я думаю что поиск папок рекурсивно это редкий случай, а для обслуживания этого варианта приходится делать дополнительные механизмы.
2. Параметры по умолчанию для папок и файлов различаются. По умолчанию папку лучше получить без вложенных папок. Ну и как я уже говорил выше возможны несовместимые параметры.
3. При получении папок и файлов для отображения в TreeView они должны быть особо сортированными то есть папки сверху, файлы снизу, соответственно должна быть вторая колонка определяющая чем является объект, чтобы папки выстроить сверху, а файлы снизу, но для дерева проводника это не экономично, потому что нет смысла получать всё, если пользователь откроет только отдельный каталог, правильнее динамически запрашивать текущие данные каталога. Поэтому не нахожу причин делать функции две в одной.
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
Тест на версии 3.3.9.19

найдено файлов = 163258
Путь поиска = C:
маска = *
_FileListToArrayRec = 11.84
_FO_FileSearch = 6.35


найдено файлов = 3319
Путь поиска = C:
маска = exe
_FileListToArrayRec = 8.1
_FO_FileSearch = 6.45

найдено файлов = 421
Путь поиска = C:
маска = *sys*.exe;*sys*.dll
_FileListToArrayRec = 8.34
_FO_FileSearch = 6.49

Код:
#include <File.au3>
#include <Array.au3> ; Only required to display the arrays

$timer = TimerInit()
; Local $aArray = _FileListToArrayRec(@WindowsDir, "*.exe", 1, 1)
; Local $aArray = _FileListToArrayRec(@HomeDrive, "*.exe", 1, 1)
; Local $aArray = _FileListToArrayRec(@HomeDrive, "*", 1, 1)
Local $aArray = _FileListToArrayRec(@HomeDrive, "*sys*.exe;*sys*.dll", 1, 1)
$timer = TimerDiff($timer)
_ArrayDisplay($aArray, Round($timer / 1000, 2) & ' sec')


Код:
#Include <FileOperations.au3>
#include <Array.au3> ; Only required to display the arrays

$timer = TimerInit()
; Local $aArray = _FO_FileSearch(@WindowsDir, "*.exe")
; Local $aArray = _FO_FileSearch(@HomeDrive, "*.exe")
; Local $aArray = _FO_FileSearch(@HomeDrive, "*")
Local $aArray = _FO_FileSearch(@HomeDrive, "*sys*.exe|*sys*.dll")
$timer = TimerDiff($timer)
_ArrayDisplay($aArray, Round($timer / 1000, 2) & ' sec')
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
пришлось воспользоваться функцией _FO_PathSplit
Код:
#include <array.au3>
#Include <FileOperations.au3>
$array = _FO_PathSplit('C:\Users\111111\Desktop\client_soft(13.12.13)')
_ArrayDisplay($array)

исходя из справки
$Array[1] = имя файла / каталога
в этом варианте, должно вернуть
Код:
$Array[1] = 'client_soft(13.12.13)'

но возвращает
Код:
$Array[1] = 'client_soft(13.12'

функция считает, что .13) это расширение и ставит его в третью позицию в массиве. это глюк
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Я считаю что все правильно работает. Я создал файл client_soft(13.12 и выставил расширение .13), и для моей ситуации функция правильно сработала.
Интересная ситуация, мне кажется не решаемая.
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
ну да. точка это начало расширения файла. но скобка..такого расширения я не видел..хотя ..все возможно в этом мире :smile:
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
Добавил функцию _FO_CreateFile
 

СН3СН2ОН

Знающий
Сообщения
78
Репутация
12
Доброго дня.
Сегодня понадобилось прошерстить комп на определенные файлы.
До этого использовал вот этот замечательный код. ( Взял тут на форуме, не помню чей).
Код:
;$iFlag = 0 - Файлы и папки (по умолчанию)
;$iFlag = 1 - Только файлы
;$iFlag = 2 - Только папки
Func _FileSearch($sPath, $sFileMask, $iFlag = 0)

    Local $sOutBin, $sOut, $aOut, $sRead, $hDir, $sAttrib

    Switch $iFlag
        Case 1
            $sAttrib = ' /A-D'
        Case 2
            $sAttrib = ' /AD'
        Case Else
            $sAttrib = ' /A'
    EndSwitch

    $sOut = StringToBinary('0' & @CRLF, 2)
    $aMasks = StringSplit($sFileMask, ';')

    For $i = 1 To $aMasks[0]
        $hDir = Run(@ComSpec & ' /U /C DIR "' & $sPath & '\' & $aMasks[$i] & '" /S /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
    Next

    $aOut = StringRegExp(BinaryToString($sOut, 2), '[^\r\n]+', 3)

    If @error Then
        Return SetError(1)
    EndIf

    $aOut[0] = UBound($aOut)-1
    Return $aOut
EndFunc

Он отлично работал, пока не засыпался на определенном диске.
Поиском нашел вашу замечательную UDF.

Собственно суть сообщения.
Вот на этом коде (я использую C: и файлы *.xml (не суть важно))
Подмешивается в начале некоторых строк в массиве не нужные символы.
Решил что возможно это важно. (функции вроде копирования файла не работают)
Система WinXP, 32bit, AutoIt 3.3.12 вроде

Код:
#include <FileOperations.au3>

Global $DirOut = 'c:\Documents and Settings\d1'

$aReturn = _FO_FileSearch($DirOut, '*.pdf')
If @error Then
	Exit
EndIf

ConsoleWrite('На диске ' & $DirOut & ' найдено ' & $aReturn[0] & ' файлов *.pdf')

For $i = 1 To $aReturn[0]
	_FindBad($aReturn[$i])
Next


Func _FindBad($string_)

	If StringInStr($string_, @CR) Then
		ConsoleWrite('БЕДА!!! найден Символ возврата каретки, Chr(13) в строке ' & $string_&@CRLF)
		Return
	EndIf

	If StringInStr($string_, @LF) Then
		ConsoleWrite('БЕДА!!! найден Символ перевода строки, Chr(10) в строке ' & $string_&@CRLF)
		Return
	EndIf


	ConsoleWrite('УРА все хорошо' & $string_&@CRLF)


EndFunc   ;==>_FindBad

Поставил пока у себя в коде обработку каждого элемента массива
Код:
$BlaBla= StringReplace($BlaBla, @CR, '')
$BlaBla= StringReplace($BlaBla, @CRLF, '')
$BlaBla= StringReplace($BlaBla, @LF, '')
 
Автор
A

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
СН3СН2ОН
Надо переписывать версию для AutoIt v3.3.12. Я начал неделю назад и бросил. В регулярных выражениях изменился тип переноса строк, теперь он не \r\n, а \n. Чтобы вернуть обратно в стиль \r\n, нужно в каждом регулярном выражении вставить флаг (*CRLF), хотя не в каждом, а тех, которые обрабатывают многострочный список. Моя идея была переработать полностью, а именно изменение в поведении флага "i", теперь он работает и для кириллицы и не требуется отдельная функция для этого функционала.

И ещё, смотрите функцию _FileListToArrayRec, добавленную в AutoIt v3.3.12, она как раз для рекурсивного поиска, возможно там достаточно флагов. Вот описание её предыдущей версии на русском языке перед тем как она была добавлена в UDF.
 
Верх