Что нового

[Автоматизация] Поиск файлов рекурсивно по данному списку

Tosyk

Чайник
Сообщения
156
Репутация
0
Версия AutoIt: 3.5.4

Описание: есть 2 типа списков с именами файлов, выглядят вот так:
первый
Код:
Material B7E671143D244B
====================================
TEXT 2F3139D816C34D 1
TEXT B6A968EF2505A2 1
TEXT 35206697A04F91 1
TEXT EB485AF490D83D 1
TEXT 0DAB42294BD9B3 1
TEXT 3D6525BEE360E1 0

Material D6906B886B06E3
====================================
TEXT 0CCECCCCFB62AE 1
TEXT 1E14CB29AB43F0 1
TEXT FB7F0DCE9B5950 1

Material 431831490FD5C9
====================================
TEXT 9D77B6474696D8 1
TEXT D04DEE5DF130A4 1
TEXT B6A968EF2505A2 1
TEXT 8C37245A4F0F81 1
TEXT A39FAFFC5ABC06 1
TEXT D24199644F2EE6 1
второй
Код:
============================================================
ant-plastic-storage-bin-c_tmp0
============================================================
cit-storage-bins-01-color
cit-storage-bins-01-normal_dx10
cit-storage-bins-01-roughness_dx10
missingtexture_dx10
это обычные текстовые файлы.

нужно создать EXE, на который мы перетаскиваем один из этих списков (или оба, в цикл) в эксплорере и запускается процесс поиска этих файлов по имени в данной структуре каталогов, расширение может быть любым. после завершения поиска файлы нужно скопировать в папку к исходному файлу.
ищем в данной структуре по пути заданномe в INI файле, который лежит рядом с EXE

Примечания: я тут нашёл, кое-что интересное вот тут: https://www.autoitscript.com/forum/topic/186400-recursive-file-search/

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

Global $hFilePath = 'C:\Drivers'

Global $aSearch = _FileListToArrayRec ($hFilePath, "*.inf", 1, 1, 1, 1)

Global $aArray[UBound($aSearch)][3]
For $x = 1 To $aSearch[0]
    $aArray[$x][0] = $hFilePath & '\' & $aSearch[$x]
    $aArray[$x][1] = StringLeft($aSearch[$x], StringInStr($aSearch[$x], '\') - 1)
    $aArray[$x][2] = IniRead($aSearch[$x], 'Version', 'Class', 'Misc')
Next
$aArray[0][0] = UBound($aArray) - 1
_ArrayDisplay($aArray, ".inf Files")

Global $sFileText = @ScriptDir & "\Examples.csv"
Global $hFileText = FileOpen($sFileText, 2)
If $hFileText = -1 Then
    ConsoleWrite('Error opening: ' & $sFileText & @CRLF)
    Exit
EndIf

_FileWriteFromArray($hFileText, $aArray, 1, Default, ',')

FileClose($hFileText)


но моя проблема в этих непонятных [ 0 ]. я уже много чего знаю и эти массивы одна из моих бед - поэтому я прошу помощи у вас
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
помогите, товарищи :-\
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
xXx сказал(а):
И что в этих списках есть файлы?
в первом списке все строчки вида:
Код:
TEXT 2F3139D816C34D 1
содержат имена файлов, само имя файла это "2F3139D816C34D" слово TEXT и цифру 1 нужно игнорировать, строки с Material и знаки равно нужно игнорировать:
Код:
Material B7E671143D244B
====================================
во втором списке строчки между знаками равно "==" и сами знаки равно нужно игнорировать:
Код:
============================================================
ant-plastic-storage-bin-c_tmp0
============================================================
но зато всё остальное - это имена файлов



xXx сказал(а):
В какой структуре?
структура любая: хоть две папки хоть 100. там могут быть пробелы и русские символы



xXx сказал(а):
файл ini должен лежать рядом со скриптом и быть вида:
Код:
"D:\folder\Длинный путь\FILE_SCTRUCTURE_STARTS_FROM_HERE"
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
xXx сказал(а):
Да как же вам помогать-то, если прочитав ваше техзадание возникает больше вопросов чем ответов.
приветствую, хотел узнать не нашли ли вы ещё время посмотреть?
или ещё какие-то вопросы может
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Давай с начала. Я понял так, что тебе нужно при перетаскивании файла на скомпилированный скрипт ***.exe, перебрать строки в перенесенном файле и выбрать все что находится между "TEXT" и "1", то есть с строки "TEXT 2F3139D816C34D 1" чтобы получилось строка "2F3139D816C34D". Правильно? Если да то что дальше с этими строками (текстом) делать?
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
IMStrelcov сказал(а):
Правильно? Если да то что дальше с этими строками (текстом) делать?
да, правильно
после этого:

- принять "2F3139D816C34D" за имя файла
- найти все файлы с таким именем
- скопировать все найденные файлы в папку с исходным файлом
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Тогда последнее, где производить поиск, в папке со скриптом или другой определенной папке, и искать ли в подпапках?
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
IMStrelcov сказал(а):
Тогда последнее, где производить поиск, в папке со скриптом или другой определенной папке, и искать ли в подпапках?
нужно искать в папке написанной в ini файле, который лежит рядом со скриптом. искать нужно рекурсивно, т.е. да - и в подпапках тоже
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Пробуй, я не тестил, только что накидал
Код:
#cs
;файл .ini переименую так же как и имя скрипта или скомпилированого .exe
;и внеси туда эти строки
[Setting]
;поставь один или более, если файлы при копировании нужно перезаписывать
Replace=0
;укажи путь к папке в которой искать файлы
Folder=''
;поставь один или более, если нужно искать в подпапках
SubDir=0
;поставь один или более, если при копировании нужно соблюдать вложенность подпапок
Build=0
#ce

Global $sIni = StringRegExpReplace(@ScriptDir, '(^.*)\.(.*)$', '$1')& '.ini'

Global $iReplace = IniRead ($sIni, 'Setting', 'Replace', 0)
Global $sFolder = IniRead ($sIni, 'Setting', 'Folder', @ScriptDir)
Global $iSubDir = IniRead ($sIni, 'Setting', 'SubDir', 0)
Global $iBuild = IniRead ($sIni, 'Setting', 'Build', 0)

Main_()

Func Main_()
	If $CmdLine[0] Then
		Local $i_Num
		For $i_Num = 1 To $CmdLine[0]
			FileRead_($CmdLine[$i_Num])
		Next
	EndIf
EndFunc

Func FileRead_($s_File)
	Local $h_File = FileOpen($s_File)
	Local $s_String, $i_Pos
	While 1
		$s_String = FileReadLine($h_File)
		If @error Then
			FileClose($h_File)
			ExitLoop
		EndIf
		If StringInStr($s_String, 'TEXT ') Then
			$s_String = StringRegExpReplace($s_String, '(^.*)\TEXT (.*)$', '$2')
			$s_String = StringRegExpReplace($s_String, '(^.*)\ (.*)$', '$1')
			FileSearch_($sFolder, $s_String)
		EndIf
	WEnd
EndFunc

Func FileSearch_($s_Folder, ByRef $s_File)
	Local $h_Find = FileFindFirstFile($s_Folder& '\*.*')
	Local $s_Find, $s_Name
	While 1
		$s_Find = FileFindNextFile($h_Find)
		If @error Then
			FileClose($h_Find)
			ExitLoop
		EndIf
		If StringInStr(FileGetAttrib($s_Folder& '\'& $s_Find) , 'D') Then
			If $iSubDir Then
				FileSearch_($s_Folder& '\'& $s_Find, $s_File)
			EndIf
		Else
			$s_Name = StringRegExpReplace($s_Find, '(^.*)\.(.*)$', '$1')
			If $s_Name = $s_File Then
				FileCopy_($s_Folder& '\'& $s_Find)
			EndIf
		EndIf
	WEnd
EndFunc

Func FileCopy_($s_FileIn)
	Local $sFileOut
	If $iBuild Then
		$sFileOut = StringReplace($s_FileIn, $sFolder, @ScriptDir& '\Backup')
	Else
		$sFileOut = @ScriptDir& '\Backup\'& StringRegExpReplace($s_FileIn, '(^.*)\\(.*)$', '$2')
	EndIf
	FileCopy($s_FileIn, $sFileOut, $iReplace ? 9 : 8)
EndFunc



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

Нашел свою опечатку, замени
Код:
Global $sIni = StringRegExpReplace(@ScriptDir, '(^.*)\.(.*)$', '$1')& '.ini'

на
Код:
Global $sIni = StringRegExpReplace(@ScriptFullPath, '(^.*)\.(.*)$', '$1')& '.ini'
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
работает как надо. только при копировании структура соблюдается при любом значении параметра build
и ещё, заметил, что у меня помимо разного разрешения у некоторых файлов есть ещё дополнительно суффикс _dx10, т.е. названия файлов выглядят как "2F3139D816C34D_dx10"
вы можете этот суфикс учесть в скрипте?
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Исправил держи, пробуй.
Код:
#cs
;файл .ini переименую так же как и имя скрипта или скомпилированого .exe
;и внеси туда эти строки
[Setting]
;поставь один или более, если файлы при копировании нужно перезаписывать
Replace=0
;укажи путь к папке в которой искать файлы
Folder=''
;поставь один или более, если нужно искать в подпапках
SubDir=0
;поставь один или более, если при копировании нужно соблюдать вложенность подпапок
Build=0
#ce

Global $sIni = StringRegExpReplace(@ScriptFullPath, '(^.*)\.(.*)$', '$1')& '.ini'

Global $iReplace = Int(IniRead ($sIni, 'Setting', 'Replace', 0))
Global $sFolder = IniRead ($sIni, 'Setting', 'Folder', @ScriptDir)
Global $iSubDir = Int(IniRead ($sIni, 'Setting', 'SubDir', 0))
Global $iBuild = Int(IniRead ($sIni, 'Setting', 'Build', 0))

Main_()

Func Main_()
	If $CmdLine[0] Then
		Local $i_Num
		For $i_Num = 1 To $CmdLine[0]
			FileRead_($CmdLine[$i_Num])
		Next
	EndIf
EndFunc

Func FileRead_($s_File)
	Local $h_File = FileOpen($s_File)
	Local $s_String, $i_Pos
	While 1
		$s_String = FileReadLine($h_File)
		If @error Then
			FileClose($h_File)
			ExitLoop
		EndIf
		If StringInStr($s_String, 'TEXT ') Then
			$s_String = StringRegExpReplace($s_String, '(^.*)\TEXT (.*)$', '$2')
			$s_String = StringRegExpReplace($s_String, '(^.*)\ (.*)$', '$1')
			FileSearch_($sFolder, $s_String)
		EndIf
	WEnd
EndFunc

Func FileSearch_($s_Folder, ByRef $s_File)
	Local $h_Find = FileFindFirstFile($s_Folder& '\*.*')
	Local $s_Find, $s_Name
	While 1
		$s_Find = FileFindNextFile($h_Find)
		If @error Then
			FileClose($h_Find)
			ExitLoop
		EndIf
		If StringInStr(FileGetAttrib($s_Folder& '\'& $s_Find) , 'D') Then
			If $iSubDir Then
				FileSearch_($s_Folder& '\'& $s_Find, $s_File)
			EndIf
		Else
			$s_Name = StringRegExpReplace($s_Find, '(^.*)\.(.*)$', '$1')
			If ($s_Name = $s_File) Or ($s_Name = $s_File& '_dx10') Then
				FileCopy_($s_Folder& '\'& $s_Find)
			EndIf
		EndIf
	WEnd
EndFunc

Func FileCopy_($s_FileIn)
	Local $sFileOut
	If $iBuild Then
		$sFileOut = StringReplace($s_FileIn, $sFolder, @ScriptDir& '\Backup')
	Else
		$sFileOut = @ScriptDir& '\Backup\'& StringRegExpReplace($s_FileIn, '(^.*)\\(.*)$', '$2')
	EndIf
	FileCopy($s_FileIn, $sFileOut, $iReplace ? 9 : 8)
EndFunc
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
IMStrelcov сказал(а):
Исправил держи, пробуй
всё сработало! а можно как-то ускорить поиск(?):
может быть при нахождении одного имени файла уже не искать такой же?
возможно при запуске скрипта формировать список файлов через командную строку, искать в этом списке и копировать найденное
или как-то ещё оптимизировать?

у меня Файлов: 36 454; папок: 8 273
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Можно, но не гарантирую быстрого ответа, так как времени свободного мало.
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
IMStrelcov сказал(а):
Можно, но не гарантирую быстрого ответа, так как времени свободного мало.
спасибо, вот в этом сообщении я высказываю идеи как ускорить поиск
http://autoit-script.ru/index.php?topic=26970.msg148587#msg148587
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Пробуй так, но чем больше файлов, тем больше оперативки потребуется для хранения списка уже скопированных файлов (думаю не критично).
Код:
#cs
;файл .ini переименую так же как и имя скрипта или скомпилированого .exe
;и внеси туда эти строки
[Setting]
;поставь один или более, если файлы при копировании нужно перезаписывать
Replace=0
;укажи путь к папке в которой искать файлы
Folder=''
;поставь один или более, если нужно искать в подпапках
SubDir=0
;поставь один или более, если при копировании нужно соблюдать вложенность подпапок
Build=0
#ce

Global $sBuffer = '|'
Global $sIni = StringRegExpReplace(@ScriptFullPath, '(^.*)\.(.*)$', '$1')& '.ini'

Global $iReplace = Int(IniRead ($sIni, 'Setting', 'Replace', 0))
Global $sFolder = IniRead ($sIni, 'Setting', 'Folder', @ScriptDir)
Global $iSubDir = Int(IniRead ($sIni, 'Setting', 'SubDir', 0))
Global $iBuild = Int(IniRead ($sIni, 'Setting', 'Build', 0))

Main_()

Func Main_()
    If $CmdLine[0] Then
        Local $i_Num
        For $i_Num = 1 To $CmdLine[0]
            FileRead_($CmdLine[$i_Num])
        Next
    EndIf
EndFunc

Func FileRead_($s_File)
    Local $h_File = FileOpen($s_File)
    Local $s_String, $i_Pos
    While 1
        $s_String = FileReadLine($h_File)
        If @error Then
            FileClose($h_File)
            ExitLoop
        EndIf
        If StringInStr($s_String, 'TEXT ') Then
            $s_String = StringRegExpReplace($s_String, '(^.*)\TEXT (.*)$', '$2')
            $s_String = StringRegExpReplace($s_String, '(^.*)\ (.*)$', '$1')
			If Not StringInStr($sBuffer, '|'& $s_String& '|') Then
				FileSearch_($sFolder, $s_String)
			EndIf
        EndIf
    WEnd
EndFunc

Func FileSearch_($s_Folder, ByRef $s_File)
    Local $h_Find = FileFindFirstFile($s_Folder& '\*.*')
    Local $s_Find, $s_Name
    While 1
        $s_Find = FileFindNextFile($h_Find)
        If @error Then
            ExitLoop
        EndIf
        If StringInStr(FileGetAttrib($s_Folder& '\'& $s_Find) , 'D') Then
            If $iSubDir Then
                FileSearch_($s_Folder& '\'& $s_Find, $s_File)
            EndIf
        Else
            $s_Name = StringRegExpReplace($s_Find, '(^.*)\.(.*)$', '$1')
            If ($s_Name = $s_File) Or ($s_Name = $s_File& '_dx10') Then
				$sBuffer &= $s_File& '|'
                FileCopy_($s_Folder& '\'& $s_Find)
				ExitLoop
            EndIf
        EndIf
    WEnd
	FileClose($h_Find)
EndFunc

Func FileCopy_($s_FileIn)
    Local $sFileOut
    If $iBuild Then
        $sFileOut = StringReplace($s_FileIn, $sFolder, @ScriptDir& '\Backup')
    Else
        $sFileOut = @ScriptDir& '\Backup\'& StringRegExpReplace($s_FileIn, '(^.*)\\(.*)$', '$2')
    EndIf
    FileCopy($s_FileIn, $sFileOut, $iReplace ? 9 : 8)
EndFunc
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
кажется, что работает точно так же :-\

я думал будет проще физически создать список файлов на жёстком диске и искать именно в нём:
типа скрипт при первом запуске создаёт такой список (там просто полные пути до файлов) и все дальнейшие операции поиска проводит именно в нём, а при нахождении совпадений копирует найденное. само собой при первом запуске он может отработать медленнее, но зато вся остальная работа будет быстрее... как мне кажется :scratch:
 

AZJIO

Меценат
Меценат
Сообщения
2 748
Репутация
1 145
Tosyk
Я когда то писал Search_files_list, но просить меня адаптировать не надо, я не готов тратить время.


Tosyk [url_ex=javascript:qq.OpenLink('http://autoit-script.ru/index.php?topic=26970.msg148637#msg148637')][?][/url_ex]
я думал будет проще физически создать список файлов на жёстком диске и искать именно в нём:
теоретически список и так на диске и поиск файлов осуществляется по древовидному списку (база данных). Теоретически по скорости он должен быть быстрей чем поиск по плоскому списку включающий в себя пути. Хотя кто знает, там же база содержит адреса к контенту и поиск по базе с лишней инфой и диск имеет маленькую память кэша, а вот если вытащить базу создав сокращённую, возможно так и действует Everything
 
Автор
Tosyk

Tosyk

Чайник
Сообщения
156
Репутация
0
AZJIO сказал(а):
Tosyk
Я когда то писал Search_files_list, но просить меня адаптировать не надо, я не готов тратить время.
<...>
спасибо. у меня задача именно автоматизировать - кидаем исходный файл с именами файлов на скрипт, получаем эти файлы рядом с исходным файлом.
что-то вводить вручную, копировать вручную - это уже в сторону от автоматизации :-\
 

IMStrelcov

CTPEJIbLLOB
Сообщения
76
Репутация
5
Думаю твоя идея не принесет нужного результата.
Объясняю/предполагаю:
Создав список всех файлов и путей к ним в отдельном файле, этот список нужно будет подгрузить и создать массив файлов/путей к ним, при этом кол-во этих файлов/путей может быть огромен, что значительно повлияет на расход оперативной памяти, а поиск по массиву приблизительно будет такой же по скорости как и без него.
Можно конечно еще этот список сокращать, удаляя из него уже найденные файлы, но тогда его каждый раз нужно будет сбрасывать в файл при каждом завершении работы программы/скрипта.
Но если есть сомнения я напишу код, только чуть попозже.
 
Верх